For example, consider this:
int index = (int) Double.NaN;
I assumed that Java would throw some kind of overflow exception but, no, you get index == 0! I can imagine a program where I try to calculate an index based on a floating point number. When the floating point number becomes NaN your index becomes zero, which would be a valid value. Your program would continue and the error would manifest itself in some irrelevant place.
Before you use any math library, test it to gain insight in its behavior. This is especially critical if you plan to write software with a lot of numerical operations. Write wrapper methods that throw exceptions to aid debugging.
Below is a test class containing interesting test cases that I could think of, written with JUnit.
package math;
import org.junit.Test;
/**
* Interesting Math library tests, some of which result in unexpected behavior.
*
* @author skorkmaz, 2013
*/
public class MathTest {
@Test
public void testDivisionByZeroInt() {
System.out.println("Test: Division by zero. int result = 1 / 0");
try {
int result = 1 / 0;
} catch (ArithmeticException e) {
/*Throws exception as I would normally expect.*/
System.out.println(e.toString());
}
System.out.println("-------------------------------------------------");
}
@Test
public void testDivisionByZeroInt2() {
System.out.println("Test: Division by zero. int result = (int) (1.0/0)");
int result = (int) (1.0 / 0);
/*No exception is thrown!*/
System.out.println("result = " + result);
System.out.println("-------------------------------------------------");
}
@Test
public void testDivisionByZeroDouble() {
System.out.println("Test: Division by zero. double result = 1.0/0");
double result = 1.0 / 0;
/*No exception is thrown!*/
System.out.println("result = " + result);
System.out.println("-------------------------------------------------");
}
@Test
public void testDivisionByZeroDoubleNaN() {
System.out.println("Test: Division by zero. double result = Double.NaN/0");
double result = Double.NaN/0;
/*No exception is thrown!*/
System.out.println("result = " + result);
System.out.println("-------------------------------------------------");
}
@Test
public void testPowDoubleNaN() {
System.out.println("Test: Pow Double.Nan. double result = Math.pow(Double.NaN, 0)");
double result = Math.pow(Double.NaN, 0);
/*No exception is thrown and returns 1.0!*/
System.out.println("result = " + result);
System.out.println("-------------------------------------------------");
}
@Test
public void testIntegerOverflowLong() {
System.out.println("Test: Integer overflow from long. int result = (int) Long.MAX_VALUE");
int result = (int) Long.MAX_VALUE;
/*No exception is thrown, result = -1!*/
System.out.println("result = " + result);
System.out.println("-------------------------------------------------");
}
@Test
public void testIntegerOverflowDouble() {
System.out.println("Test: Integer overflow from double. int result = (int) Double.MAX_VALUE");
int result = (int) Double.MAX_VALUE;
/*No exception is thrown, result = 2147483647 (Integer.MAX_VALUE)!*/
System.out.println("result = " + result);
System.out.println("-------------------------------------------------");
}
@Test
public void testIntegerOverflowNaN() {
System.out.println("Test: Integer overflow from NaN. int result = (int) Double.NaN");
int result = (int) Double.NaN;
/*No exception is thrown and it returns 0 which may mask possible problems!*/
System.out.println("result = " + result);
System.out.println("-------------------------------------------------");
}
@Test
public void testNaNComparison() {
System.out.println("Test: NaN comparison. boolean result = Double.NaN == Double.NaN");
boolean result = Double.NaN == Double.NaN;
/*Returns false*/
System.out.println("result = " + result);
System.out.println("-------------------------------------------------");
}
@Test
public void testSqrtNegative() {
System.out.println("Test: sqrt(negative). double result = Math.sqrt(-1)");
double result = Math.sqrt(-1);
/*No exception is thrown!*/
System.out.println("result = " + result);
System.out.println("-------------------------------------------------");
}
@Test
public void testZeroComparison() {
System.out.println("Test: Zero comparison. double result = 0.0 == -0.0");
boolean result = 0.0 == -0.0;
System.out.println("result = " + result);
System.out.println("-------------------------------------------------");
}
@Test
public void testZeroTimesInf() {
System.out.println("Test: Zero * inf. double result = 0.0 * Double.POSITIVE_INFINITY");
double result = 0.0 * Double.POSITIVE_INFINITY;
/*No exception is thrown!*/
System.out.println("result = " + result);
System.out.println("-------------------------------------------------");
}
@Test
public void testInfDivZero() {
System.out.println("Test: inf/zero. double result = Double.POSITIVE_INFINITY / 0.0");
double result = Double.POSITIVE_INFINITY / 0.0;
/*No exception is thrown!*/
System.out.println("result = " + result);
System.out.println("-------------------------------------------------");
}
@Test
public void testInfDivNaN() {
System.out.println("Test: inf/NaN. double result = Double.POSITIVE_INFINITY / Double.NaN");
double result = Double.POSITIVE_INFINITY / Double.NaN;
/*No exception is thrown!*/
System.out.println("result = " + result);
System.out.println("-------------------------------------------------");
}
@Test
public void testInfDivInf() {
System.out.println("Test: inf/inf. double result = Double.POSITIVE_INFINITY / Double.POSITIVE_INFINITY");
double result = Double.POSITIVE_INFINITY / Double.POSITIVE_INFINITY;
/*No exception is thrown!*/
System.out.println("result = " + result);
System.out.println("-------------------------------------------------");
}
}
No comments:
Post a Comment