Index: Lib/test/test_jy_internals.py =================================================================== RCS file: /cvsroot/jython/jython/Lib/test/test_jy_internals.py,v retrieving revision 2.2 diff -u -r2.2 test_jy_internals.py --- Lib/test/test_jy_internals.py 10 Nov 2003 18:55:28 -0000 2.2 +++ Lib/test/test_jy_internals.py 19 Dec 2003 23:21:26 -0000 @@ -85,7 +85,26 @@ for y in [0,255]: assert float((v+d)*256+y) == (((v+d)*256+y)*256).scaledDoubleValue(e) assert e[0] == 1 - + +class ExtraMathTests(unittest.TestCase): + def test_epsilon(self): + from org.python.core import ExtraMath + self.assertNotEqual(1.0 + ExtraMath.EPSILON, 1.0) + self.assertEqual(1.0 + (ExtraMath.EPSILON/2.0), 1.0) + def test_close(self): + from org.python.core import ExtraMath + self.assert_(ExtraMath.close(3.0, 3.0)) + self.assert_(ExtraMath.close(3.0, 3.0 + ExtraMath.CLOSE)) + self.assert_(not ExtraMath.close(3.0, 3.0 + 4.0*ExtraMath.CLOSE)) + def test_closeFloor(self): + from org.python.core import ExtraMath + import math + self.assertEquals(ExtraMath.closeFloor(3.5), 3.0) + self.assertEquals(ExtraMath.closeFloor(3.0 - ExtraMath.EPSILON), 3.0) + self.assertEquals( + ExtraMath.closeFloor(3.0 - 3.0 * ExtraMath.CLOSE), 2.0) + self.assertEquals(ExtraMath.closeFloor(math.log10(10**3)), 3.0) + def test_main(): test_suite = unittest.TestSuite() test_loader = unittest.TestLoader() @@ -93,6 +112,7 @@ test_suite.addTest(test_loader.loadTestsFromTestCase(case)) suite_add(WeakIdentityMapTests) suite_add(LongAsScaledDoubleValueTests) + suite_add(ExtraMathTests) run_suite(test_suite) if __name__ == "__main__": Index: org/python/core/ExtraMath.java =================================================================== RCS file: /cvsroot/jython/jython/org/python/core/ExtraMath.java,v retrieving revision 2.3 diff -u -r2.3 ExtraMath.java --- org/python/core/ExtraMath.java 28 Oct 2001 17:13:42 -0000 2.3 +++ org/python/core/ExtraMath.java 19 Dec 2003 23:21:26 -0000 @@ -6,7 +6,9 @@ * A static utility class with two additional math functions. */ public class ExtraMath { - static double LOG10 = Math.log(10.0); + public static double LOG10 = Math.log(10.0); + public static double EPSILON = Math.pow(2.0, -52.0); + public static double CLOSE = EPSILON * 2.0; public static double log10(double v) { return Math.log(v) / LOG10; @@ -26,5 +28,31 @@ double wv = w/v; return v * Math.sqrt(1.0 + wv*wv); } + } + + /** + * Are v and w "close" to each other? Uses a scaled tolerance. + */ + public static boolean close(double v, double w, double tol) { + if (v == w) + { + return true; + } + double scaled = tol * (Math.abs(v) + Math.abs(w))/2.0; + return Math.abs(w - v) < scaled; + } + + public static boolean close(double v, double w) + { + return close(v, w, CLOSE); + } + + /** + * Returns floor(v) except when v is very close to the next number, + * when it returns ceil(v); + */ + public static double closeFloor(double v) { + double floor = Math.floor(v); + return close(v, floor + 1.0) ? floor + 1.0 : floor; } } Index: org/python/core/PyString.java =================================================================== RCS file: /cvsroot/jython/jython/org/python/core/PyString.java,v retrieving revision 2.61 diff -u -r2.61 PyString.java --- org/python/core/PyString.java 11 Jul 2003 22:10:31 -0000 2.61 +++ org/python/core/PyString.java 19 Dec 2003 23:21:27 -0000 @@ -2040,7 +2040,7 @@ } double power = 0.0; if (v > 0) - power = Math.floor(Math.log(v)/Math.log(10)); + power = ExtraMath.closeFloor(ExtraMath.log10(v)); //System.err.println("formatExp: "+v+", "+power); int savePrecision = precision;