Hi Andrew and Pekka, Thank you for your efforts (regarding patch for Collections.emptySet/Map/List).
To continue pushing the patches, I've cherry-picked 2 patches (to https://github.com/ivmai/classpath/tree/ivmai4review-v3) containing StrictMath fixes and the corresponding tests: https://github.com/ivmai/classpath/commit/b0103d175bb012fcec411cc9e76257f3f257c39d (StrictMath changes) https://github.com/ivmai/classpath/commit/214c8bab72dc4689edf7ae1cd49e3a109c0746d7 (StrictMath test) Some notes: - In the 1st patch I've removed several trailing spaces at EOLn in ChangeLog - I think it is ok not to post this as a separate patch - In the 2nd patch I've also fixed java.lang.reflect/ArrayTest (a one-line fix - I've commented out loadLibrary call but it might be better to remove this line at all) 1st patch (ChangeLog diff is omitted): commit b0103d175bb012fcec411cc9e76257f3f257c39d Author: Ivan Maidanski <iv...@mail.ru> Date: Tue Jul 19 21:14:16 2011 +0400 Fix bugs in several StrictMath methods 2011-07-19 Ivan Maidanski <iv...@mail.ru> * java/lang/StrictMath.java: (acos(double)): Bug fix for x <= -1/2 case. (atan(double)): Fix documentation typo. (pow(double,double)): Fix a comment; put y == 1/2 case handling after x == -0 case (since pow(-0, 1/2) == 0 but sqrt(-0) == -0); return -0 (or -INF) for pow(-0, 2*k) where k is non-zero integer; simplify expression for "negative" variable. (IEEEremainder(double,double)): Bug fix for x == -0 and x == -|y| cases; bug fix for |y| >= 2**-1021 and |x| > |y|/2. (remPiOver2(double[],double[],int,int)): Reset "recompute" at the beginning of every do/while iteration. (tan(double,double,boolean)): Negate the result if x <= -0.6744. diff --git a/java/lang/StrictMath.java b/java/lang/StrictMath.java index 88f5e57..b4fe411 100644 --- a/java/lang/StrictMath.java +++ b/java/lang/StrictMath.java @@ -1,5 +1,6 @@ /* java.lang.StrictMath -- common mathematical functions, strict Java - Copyright (C) 1998, 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + Copyright (C) 1998, 2001, 2002, 2003, 2006, 2010 + Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -456,9 +457,10 @@ public final strictfp class StrictMath double r = x - (PI_L / 2 - x * (p / q)); return negative ? PI / 2 + r : PI / 2 - r; } + double z = (1 - x) * 0.5; if (negative) // x<=-0.5. { - double z = (1 + x) * 0.5; + // z = (1+orig_x)*0.5 double p = z * (PS0 + z * (PS1 + z * (PS2 + z * (PS3 + z * (PS4 + z * PS5))))); double q = 1 + z * (QS1 + z * (QS2 + z * (QS3 + z * QS4))); @@ -466,8 +468,7 @@ public final strictfp class StrictMath double w = p / q * s - PI_L / 2; return PI - 2 * (s + w); } - double z = (1 - x) * 0.5; // x>0.5. - double s = sqrt(z); + double s = sqrt(z); // x>=0.5 double df = (float) s; double c = (z - df * df) / (s + df); double p = z * (PS0 + z * (PS1 + z * (PS2 + z * (PS3 + z @@ -478,12 +479,12 @@ public final strictfp class StrictMath } /** - * The trigonometric function <em>arcsin</em>. The range of angles returned + * The trigonometric function <em>arctan</em>. The range of angles returned * is -pi/2 to pi/2 radians (-90 to 90 degrees). If the argument is NaN, the * result is NaN; and the arctangent of 0 retains its sign. * * @param x the tan to turn back into an angle - * @return arcsin(x) + * @return arctan(x) * @see #atan2(double, double) */ public static double atan(double x) @@ -1520,8 +1521,8 @@ public final strictfp class StrictMath if (x != x || y != y) return Double.NaN; - // When x < 0, yisint tells if y is not an integer (0), even(1), - // or odd (2). + // When x < 0, yisint tells if y is not an integer (0), odd (1), + // or even (2). int yisint = 0; if (x < 0 && floor(y) == y) yisint = (y % 2 == 0) ? 2 : 1; @@ -1539,8 +1540,6 @@ public final strictfp class StrictMath } if (y == 2) return x * x; - if (y == 0.5) - return sqrt(x); // More special cases, of x. if (x == 0 || ax == Double.POSITIVE_INFINITY || ax == 1) @@ -1554,10 +1553,18 @@ public final strictfp class StrictMath else if (yisint == 1) ax = -ax; } + else + { + // Check for x == -0 with odd y. + if (1 / x < 0 && ay % 2 == 1) // yisint cannot be used here + ax = -ax; + } return ax; } if (x < 0 && yisint == 0) return Double.NaN; + if (y == 0.5) // x!=0 + return sqrt(x); // Now we can start! double t; @@ -1639,7 +1646,7 @@ public final strictfp class StrictMath } // Split up y into y1+y2 and compute (y1+y2)*(t1+t2). - boolean negative = x < 0 && yisint == 1; + boolean negative = yisint == 1; // Implies x<0. double y1 = (float) y; double p_l = (y - y1) * t1 + y * t2; double p_h = y1 * t1; @@ -1690,12 +1697,14 @@ public final strictfp class StrictMath if (x == Double.NEGATIVE_INFINITY || ! (x < Double.POSITIVE_INFINITY) || y == 0 || y != y) return Double.NaN; + if (x == 0) // Filter out -0 case. + return x; + if (x == y || -x == y) + return 0 * x; // Get correct sign. boolean negative = x < 0; x = abs(x); y = abs(y); - if (x == y || x == 0) - return 0 * x; // Get correct sign. // Achieve x < 2y, then take first shot at remainder. if (y < TWO_1023) @@ -1713,11 +1722,11 @@ public final strictfp class StrictMath } else { - y *= 0.5; - if (x > y) + double half = y * 0.5; + if (x > half) { x -= y; - if (x >= y) + if (x >= half) x -= y; } } @@ -2186,7 +2195,7 @@ public final strictfp class StrictMath int[] iq = new int[20]; double[] f = new double[20]; double[] q = new double[20]; - boolean recompute = false; + boolean recompute; // Initialize jk, jz, jv, q0; note that 3>q0. int jk = 4; @@ -2210,6 +2219,7 @@ public final strictfp class StrictMath do { + recompute = false; // Distill q[] into iq[] reversingly. for (i = 0, j = jz, z = q[jz]; j > 0; i++, j--) { @@ -2482,15 +2492,16 @@ public final strictfp class StrictMath v = invert ? -1 : 1; return (negative ? -1 : 1) * (v - 2 * (x - (w * w / (w + v) - r))); } - if (! invert) - return w; - - // Compute -1.0/(x+r) accurately. - z = (float) w; - v = r - (z - x); - double a = -1 / w; - double t = (float) a; - return t + a * (1 + t * z + t * v); + if (invert) + { + // Compute -1.0/(x+r) accurately. + z = (float) w; + v = r - (z - x); + double a = -1 / w; + double t = (float) a; + w = t + a * (1 + t * z + t * v); + } + return negative ? -w : w; } /** 2nd patch (ChangeLog omitted): commit 214c8bab72dc4689edf7ae1cd49e3a109c0746d7 Author: Ivan Maidanski <iv...@mail.ru> Date: Tue Jul 19 21:35:14 2011 +0400 Add StrictMath tests 2011-07-19 Ivan Maidanski <iv...@mail.ru> * test/Makefile.am: Add java.lang.reflect and java.lang to SUBDIRS. * test/java.lang/Makefile.am: New file. * test/java.lang/StrictMathTest.java: Likewise. * test/java.lang.reflect/ArrayTest.java: (main(String[])): Comment out loadLibrary() call (since this should be done by VMArray implementation). diff --git a/ChangeLog b/ChangeLog index 2b26411..cf5abf5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,14 @@ 2011-07-19 Ivan Maidanski <iv...@mail.ru> + * test/Makefile.am: Add java.lang.reflect and java.lang to SUBDIRS. + * test/java.lang/Makefile.am: New file. + * test/java.lang/StrictMathTest.java: Likewise. + * test/java.lang.reflect/ArrayTest.java: (main(String[])): Comment + out loadLibrary() call (since this should be done by VMArray + implementation). + +2011-07-19 Ivan Maidanski <iv...@mail.ru> + * java/lang/StrictMath.java: (acos(double)): Bug fix for x <= -1/2 case. (atan(double)): Fix documentation typo. diff --git a/test/Makefile.am b/test/Makefile.am index bd3972a..0a0767e 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,4 +1,4 @@ ## Input file for automake to generate the Makefile.in used by configure -SUBDIRS = java.net java.io java.util gnu.java.lang.reflect - +SUBDIRS = gnu.java.lang.reflect java.lang java.lang.reflect java.net \ + java.io java.util diff --git a/test/java.lang.reflect/ArrayTest.java b/test/java.lang.reflect/ArrayTest.java index 4433e9b..8357360 100644 --- a/test/java.lang.reflect/ArrayTest.java +++ b/test/java.lang.reflect/ArrayTest.java @@ -2,7 +2,7 @@ import java.lang.reflect.Array; public class ArrayTest { public static void main(String[] args) { - System.loadLibrary("javalangreflect"); + //System.loadLibrary("javalangreflect"); Object[] objArray = new Object[9]; boolean[] boolArray = new boolean[9]; @@ -27,7 +27,7 @@ public class ArrayTest { E.printStackTrace(); } System.out.println(": newInstance(<primitive Class>,int)"); - + try { objArray = (Object[])Array.newInstance(java.lang.Object.class, 9); System.out.print(objArray != null ? "PASSED" : "FAILED"); diff --git a/test/java.lang/Makefile.am b/test/java.lang/Makefile.am new file mode 100644 index 0000000..bbd9b0a --- /dev/null +++ b/test/java.lang/Makefile.am @@ -0,0 +1,3 @@ +## Input file for automake to generate the Makefile.in used by configure + +check_JAVA = StrictMathTest.java diff --git a/test/java.lang/StrictMathTest.java b/test/java.lang/StrictMathTest.java new file mode 100644 index 0000000..345a321 --- /dev/null +++ b/test/java.lang/StrictMathTest.java @@ -0,0 +1,131 @@ +/* StrictMathTest.java -- tests StrictMath class + Copyright (C) 2010 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +/** + * @author Ivan Maidanski + */ +public class StrictMathTest { + + public static void main(String[] args) { + acosTest(); + powTest(); // 2 tests + IEEEremainderTest(); // 2 tests + tanTest(); // 2 tests + sinTest(); // 2 tests + printStatus("StrictMath"); + } + + private static int passed; + private static int failed; + + static void printStatus(String className) { + if (failed != 0) { + System.out.println(className + " test failures statistic (" + failed + + " fails and " + passed + " passes)."); + } else { + System.out.println("PASSED: [" + className + "] All " + passed + + " tests."); + } + } + + static void assertTrue(boolean cond, String testName) { + if (cond) { + passed++; + } else { + failed++; + System.out.println("FAILED " + testName); + } + } + + static void assertEquals(long a, long b, String testName) { + assertTrue(a == b, testName); + } + + static void assertEquals(double a, double b, double prec, String testName) { + assertTrue(Math.abs(a - b) <= prec, testName); + } + + static void assertTaskNoTimeout(Runnable task, long timeoutMillis, + String testName) { + Thread thread = new Thread(task, "Task " + testName); + thread.setDaemon(true); + thread.start(); + try { + thread.join(timeoutMillis); + } catch (InterruptedException e) { + // Should not happen. + assertTrue(false, testName); + } + assertTrue(!thread.isAlive(), testName); + } + + public static void acosTest() { + assertEquals(2.2142974, StrictMath.acos(-0.6), 1e-5, "acos"); + } + + public static void powTest() { + assertEquals(0, Double.doubleToRawLongBits(StrictMath.pow(-0.0, 0.5)), + "pow"); + assertEquals(~(-1L >>> 1), + Double.doubleToRawLongBits(StrictMath.pow(-0.0, 3)), + "pow #2"); + } + + public static void IEEEremainderTest() { + assertEquals(~(-1L >>> 1), + Double.doubleToRawLongBits( + StrictMath.IEEEremainder(-0.0, 1)), + "IEEEremainder"); + assertEquals(-1.7999999, StrictMath.IEEEremainder(2, 3.8), 1E-5, + "IEEEremainder #2"); + } + + public static void sinTest() { + assertTaskNoTimeout(new Runnable() { + + public void run() { + assertEquals(0.6402884, StrictMath.sin(1.9e209), 1e-5, "sin #2"); + } + }, 1000, "sin"); + } + + public static void tanTest() { + assertEquals(-0.0290081, StrictMath.tan(-0.029), 1e-5, "tan"); + assertEquals(34.2325327, StrictMath.tan(-1.6), 1e-5, "tan #2"); + } +} Regards, Ivan