Skip to content

Instantly share code, notes, and snippets.

@ctrueden
Created February 22, 2012 17:59
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ctrueden/1886325 to your computer and use it in GitHub Desktop.
Save ctrueden/1886325 to your computer and use it in GitHub Desktop.
Benchmarks performance of several methods of detecting integer multiplication overflows.
//
// Overflows.java
//
import java.math.BigInteger;
/**
* Benchmarks performance of several methods of detecting integer overflows.
*
* @author Curtis Rueden
*/
public final class Overflows {
// -- Main method --
public static void main(final String[] args) {
// int[] iv = { Integer.MAX_VALUE / 2, 2 };
// int[] iv = { 46340, 46341 };
// int[] iv = { 46341, 46341 };
// int[] iv = { 46340, 46342 };
// int[] iv = { 65536, 32767 };
// int[] iv = { 65535, 32768 };
// int[] iv = { 65536, 32768 };
// long[] lv = { Long.MAX_VALUE / 6, 2, 3 };
final int num = 5;
final int[] iv = new int[num];
final long[] lv = new long[num];
for (int i = 0; i < num; i++) {
iv[i] = (int) (100 * Math.random());
lv[i] = (long) (1000 * Math.random());
}
final int iter = 1000000;
long start, end;
start = System.currentTimeMillis();
for (int q = 0; q < iter; q++)
safeMultiply(iv);
end = System.currentTimeMillis();
System.out.println("int (longs): " + (end - start) + " ms");
start = System.currentTimeMillis();
for (int q = 0; q < iter; q++)
safeMultiplyIntBits(iv);
end = System.currentTimeMillis();
System.out.println("int (bits): " + (end - start) + " ms");
start = System.currentTimeMillis();
for (int q = 0; q < iter; q++)
safeMultiplyBigInteger(lv);
end = System.currentTimeMillis();
System.out.println("long (BigIntegers): " + (end - start) + " ms");
start = System.currentTimeMillis();
for (int q = 0; q < iter; q++)
safeMultiplyLongBits(lv);
end = System.currentTimeMillis();
System.out.println("long (bits): " + (end - start) + " ms");
}
// -- Utility methods --
/**
* Checks that the product of the given sizes does not exceed the 32-bit
* integer limit (i.e., {@link Integer#MAX_VALUE}).
*
* @param sizes list of sizes from which to compute the product
* @return the product of the given sizes
* @throws IllegalArgumentException if the total size exceeds 2GiB, which is
* the maximum size of an int in Java; or if any size argument is
* zero or negative
*/
public static int safeMultiply(final int... sizes)
throws IllegalArgumentException
{
if (sizes.length == 0) return 0;
long total = 1;
for (final int size : sizes) {
if (size < 1) {
throw new IllegalArgumentException("Invalid array size: " +
sizeAsProduct(sizes));
}
total *= size;
if (total > Integer.MAX_VALUE) {
throw new IllegalArgumentException("Array size too large: " +
sizeAsProduct(sizes));
}
}
// NB: The cast to int is safe here, due to the checks above.
return (int) total;
}
/**
* Checks that the product of the given sizes does not exceed the 32-bit
* integer limit (i.e., {@link Integer#MAX_VALUE}).
*
* @param sizes list of sizes from which to compute the product
* @return the product of the given sizes
* @throws IllegalArgumentException if the total size exceeds 2GiB, which is
* the maximum size of an int in Java; or if any size argument is
* zero or negative
*/
public static int safeMultiplyIntBits(final int... sizes)
throws IllegalArgumentException
{
if (sizes.length == 0) return 0;
int total = 1;
for (final int size : sizes) {
if (size < 1) {
throw new IllegalArgumentException("Invalid array size: " +
sizeAsProduct(sizes));
}
if (willOverflow(total, size)) {
throw new IllegalArgumentException("Array size too large: " +
sizeAsProduct(sizes));
}
total *= size;
}
return total;
}
private static final BigInteger LONG_MAX_VALUE =
new BigInteger("" + Long.MAX_VALUE);
/**
* Checks that the product of the given sizes does not exceed the 64-bit
* integer limit (i.e., {@link Long#MAX_VALUE}).
*
* @param sizes list of sizes from which to compute the product
* @return the product of the given sizes
* @throws IllegalArgumentException if the total size exceeds 8EiB, which is
* the maximum size of a long in Java; or if any size argument is
* zero or negative
*/
public static long safeMultiplyBigInteger(final long... sizes)
throws IllegalArgumentException
{
if (sizes.length == 0) return 0;
BigInteger total = BigInteger.ONE;
for (final long size : sizes) {
if (size < 1) {
throw new IllegalArgumentException("Invalid array size: " +
sizeAsProduct(sizes));
}
total = total.multiply(new BigInteger("" + size));
if (total.compareTo(LONG_MAX_VALUE) > 0) {
throw new IllegalArgumentException("Array size too large: " +
sizeAsProduct(sizes));
}
}
// NB: The downcast to long is safe here, due to the checks above.
return total.longValue();
}
/**
* Checks that the product of the given sizes does not exceed the 64-bit
* integer limit (i.e., {@link Long#MAX_VALUE}).
*
* @param sizes list of sizes from which to compute the product
* @return the product of the given sizes
* @throws IllegalArgumentException if the total size exceeds 8EiB, which is
* the maximum size of a long in Java; or if any size argument is
* zero or negative
*/
public static long safeMultiplyLongBits(final long... sizes)
throws IllegalArgumentException
{
if (sizes.length == 0) return 0;
long total = 1;
for (final long size : sizes) {
if (size < 1) {
throw new IllegalArgumentException("Invalid array size: " +
sizeAsProduct(sizes));
}
if (willOverflow(total, size)) {
throw new IllegalArgumentException("Array size too large: " +
sizeAsProduct(sizes));
}
total *= size;
}
return total;
}
// -- Helper methods --
private static String sizeAsProduct(final int... sizes) {
final StringBuilder sb = new StringBuilder();
boolean first = true;
for (final int size : sizes) {
if (first) first = false;
else sb.append(" x ");
sb.append(size);
}
return sb.toString();
}
private static String sizeAsProduct(final long... sizes) {
final StringBuilder sb = new StringBuilder();
boolean first = true;
for (final long size : sizes) {
if (first) first = false;
else sb.append(" x ");
sb.append(size);
}
return sb.toString();
}
private static boolean willOverflow(final int v1, final int v2) {
return Integer.MAX_VALUE / v1 < v2;
}
private static boolean willOverflow(final long v1, final long v2) {
return Long.MAX_VALUE / v1 < v2;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment