You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by se...@apache.org on 2011/01/24 18:33:33 UTC

svn commit: r1062893 - /commons/proper/math/trunk/src/test/java/org/apache/commons/math/util/FastMathStrictComparisonTest.java

Author: sebb
Date: Mon Jan 24 17:33:33 2011
New Revision: 1062893

URL: http://svn.apache.org/viewvc?rev=1062893&view=rev
Log:
Check all FastMath methods against StrictMath results

Added:
    commons/proper/math/trunk/src/test/java/org/apache/commons/math/util/FastMathStrictComparisonTest.java   (with props)

Added: commons/proper/math/trunk/src/test/java/org/apache/commons/math/util/FastMathStrictComparisonTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math/util/FastMathStrictComparisonTest.java?rev=1062893&view=auto
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math/util/FastMathStrictComparisonTest.java (added)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math/util/FastMathStrictComparisonTest.java Mon Jan 24 17:33:33 2011
@@ -0,0 +1,233 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.math.util;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * Test to compare FastMath results against StrictMath results for boundary values.
+ */
+@RunWith(Parameterized.class)
+public class FastMathStrictComparisonTest {
+
+    // Values which often need special handling
+    private static final Double[] DOUBLE_SPECIAL_VALUES = {
+        -0.0, +0.0,                                         // 1,2
+        Double.NaN,                                         // 3
+        Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, // 4,5
+        -Double.MAX_VALUE, Double.MAX_VALUE,                // 6,7
+        // decreasing order of absolute value to help catch first failure
+        -MathUtils.EPSILON, MathUtils.EPSILON,              // 8,9
+        -MathUtils.SAFE_MIN, MathUtils.SAFE_MIN,            // 10,11
+        -Double.MIN_VALUE, Double.MIN_VALUE,                // 12,13
+    };
+
+    private static final Float [] FLOAT_SPECIAL_VALUES = {
+        -0.0f, +0.0f,                                       // 1,2
+        Float.NaN,                                          // 3
+        Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY,   // 4,5
+        Float.MIN_VALUE, Float.MAX_VALUE,                   // 6,7
+        -Float.MIN_VALUE, -Float.MAX_VALUE,                 // 8,9
+    };
+    
+    private static final Object [] LONG_SPECIAL_VALUES = {
+        -1,0,1,
+        Long.MIN_VALUE, Long.MAX_VALUE,
+    };
+    
+    private static final Object[] INT_SPECIAL_VALUES = {
+        -1,0,1,
+        Integer.MIN_VALUE, Integer.MAX_VALUE,
+    };
+    
+    private final Method mathMethod;
+    private final Method fastMethod;
+    private final Type[] types;
+    private final Object[][] valueArrays;
+    
+    public FastMathStrictComparisonTest(Method m, Method f, Type[] types, Object[][] data) throws Exception{
+        this.mathMethod=m;
+        this.fastMethod=f;
+        this.types=types;
+        this.valueArrays=data;
+    }
+    
+    @Test
+    public void test1() throws Exception{
+        setupMethodCall(mathMethod, fastMethod, types, valueArrays);
+    }
+    private static boolean isNumber(Double d) {
+        return !(d.isInfinite() || d.isNaN());
+    }
+
+    private static boolean isNumber(Float f) {
+        return !(f.isInfinite() || f.isNaN());
+    }
+
+    private static void reportFailedResults(Method mathMethod, Object[] params, Object expected, Object actual, int[] entries){
+        String format = null;
+        long actL=0;
+        long expL=0;
+        if (expected instanceof Double) {
+            Double exp = (Double) expected;
+            Double act = (Double) actual;
+            if (isNumber(exp) && isNumber(act)) { // show difference as hex
+                actL = Double.doubleToLongBits(act);
+                expL = Double.doubleToLongBits(exp);
+                format = "%016x";
+            }
+        } else if (expected instanceof Float ){
+            Float exp = (Float) expected;
+            Float act = (Float) actual;
+            if (isNumber(exp) && isNumber(act)) { // show difference as hex
+                actL = Float.floatToIntBits(act);
+                expL = Float.floatToIntBits(exp);
+                format = "%08x";
+            }
+        }
+        StringBuilder sb = new StringBuilder();
+        sb.append(mathMethod.getReturnType().getSimpleName());
+        sb.append(" ");
+        sb.append(mathMethod.getName());
+        sb.append("(");
+        String sep = "";
+        for(Object o : params){
+            sb.append(sep);
+            sb.append(o);
+            sep=", ";
+        }
+        sb.append(") expected ");
+        if (format != null){
+            sb.append(String.format(format, expL));                
+        } else {
+            sb.append(expected);
+        }
+        sb.append(" actual ");
+        if (format != null){
+            sb.append(String.format(format, actL));                
+        } else {
+            sb.append(actual);
+        }
+        sb.append(" entries ");
+        sb.append(Arrays.toString(entries));
+        String message = sb.toString();
+        final boolean fatal = false;
+        if (fatal) {
+            Assert.fail(message);
+        } else {
+            System.out.println(message);
+        }
+    }            
+
+    private static void callMethods(Method mathMethod, Method fastMethod,
+            Object[] params, int[] entries) throws IllegalAccessException,
+            InvocationTargetException {
+        try {
+            Object expected = mathMethod.invoke(mathMethod, params);
+            Object actual = fastMethod.invoke(mathMethod, params);
+            if (!expected.equals(actual)) {
+                reportFailedResults(mathMethod, params, expected, actual, entries);
+            }
+        } catch (IllegalArgumentException e) {
+            Assert.fail(mathMethod+" "+e);
+        }
+    }
+    
+    private static void setupMethodCall(Method mathMethod, Method fastMethod, 
+            Type[] types, Object[][] valueArrays) throws Exception {
+        Object[] params = new Object[types.length];
+        int entry1 = 0;
+        int[] entries = new int[types.length];
+        for(Object d : valueArrays[0]) {
+            entry1++;
+            params[0] = d;
+            entries[0] = entry1;
+            if (params.length > 1){
+                int entry2 = 0;
+                for(Object d1 : valueArrays[1]) {
+                    entry2++;
+                    params[1] = d1;                    
+                    entries[1] = entry2;
+                    callMethods(mathMethod, fastMethod, params, entries);                    
+                }
+            } else {
+                callMethods(mathMethod, fastMethod, params, entries);
+            }
+        }
+    }
+
+    @Parameters
+    public static List<Object[]> data() throws Exception {
+        List<Object[]> list = new ArrayList<Object[]>();
+        for(Method mathMethod : StrictMath.class.getDeclaredMethods()) {
+            method:
+            if (Modifier.isPublic(mathMethod.getModifiers())){// Only test public methods
+                Type []types = mathMethod.getGenericParameterTypes();
+                if (types.length >=1) { // Only check methods with at least one parameter
+                    try {
+                        // Get the corresponding FastMath method
+                        Method fastMethod = FastMath.class.getDeclaredMethod(mathMethod.getName(), (Class[]) types);
+                        if (Modifier.isPublic(fastMethod.getModifiers())) { // It must be public too
+                            Object [][] values = new Object[types.length][];
+                            int index = 0;
+                            for(Type t : types) {
+                                if (t.equals(double.class)){
+                                    values[index]=DOUBLE_SPECIAL_VALUES;
+                                } else if (t.equals(float.class)) {
+                                    values[index]=FLOAT_SPECIAL_VALUES;
+                                } else if (t.equals(long.class)) {
+                                    values[index]=LONG_SPECIAL_VALUES;
+                                } else if (t.equals(int.class)) {
+                                    values[index]=INT_SPECIAL_VALUES;
+                                } else {
+                                    System.out.println("Cannot handle class "+t+" for "+mathMethod);
+                                    break method;
+                                }
+                                index++;
+                            }
+//                            System.out.println(fastMethod);
+                            /*
+                             * The current implementation runs each method as a separate test.
+                             * Could be amended to run each value as a separate test
+                             */
+                            list.add(new Object[]{mathMethod, fastMethod, types, values});
+//                            setupMethodCall(mathMethod, fastMethod, params, data);
+                        } else {
+                            System.out.println("Cannot find public FastMath method corresponding to: "+mathMethod);                            
+                        }
+                    } catch (NoSuchMethodException e) {
+                        System.out.println("Cannot find FastMath method corresponding to: "+mathMethod);
+                    }
+                }
+            }
+        }
+        return list;
+    }
+
+}

Propchange: commons/proper/math/trunk/src/test/java/org/apache/commons/math/util/FastMathStrictComparisonTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/test/java/org/apache/commons/math/util/FastMathStrictComparisonTest.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision