SF.net SVN: jython:[7278] trunk/jython

[email protected] Wed, 30 Mar 2011 15:43:34 +0000
Newsgroups gmane.comp.lang.jython.cvs
Message-ID <[email protected]>
Revision: 7278
          http://jython.svn.sourceforge.net/jython/?rev=7278&view=rev
Author:   otmarhumbel
Date:     2011-03-30 15:43:34 +0000 (Wed, 30 Mar 2011)

Log Message:
-----------
upgrade most of the math module to 2.6

Modified Paths:
--------------
    trunk/jython/Lib/test/test_math_jy.py
    trunk/jython/src/org/python/compiler/Module.java
    trunk/jython/src/org/python/modules/math.java

Added Paths:
-----------
    trunk/jython/tests/java/org/python/compiler/
    trunk/jython/tests/java/org/python/compiler/ModuleTest.java
    trunk/jython/tests/java/org/python/core/PyFloatTest.java

Modified: trunk/jython/Lib/test/test_math_jy.py
===================================================================
--- trunk/jython/Lib/test/test_math_jy.py	2011-03-30 15:17:27 UTC (rev 7277)
+++ trunk/jython/Lib/test/test_math_jy.py	2011-03-30 15:43:34 UTC (rev 7278)
@@ -7,6 +7,7 @@
 from test import test_support
 
 inf = float('inf')
+ninf = float('-inf')
 nan = float('nan')
 
 class MathTestCase(unittest.TestCase):
@@ -17,7 +18,17 @@
         self.assertNotEqual(mantissa, mantissa)
         self.assertEqual(exponent, 0)
 
+    def test_fmod(self):
+        self.assertEqual(-1e-100, math.fmod(-1e-100, 1e100))
 
+    def test_hypot(self):
+        self.assert_(math.isnan(math.hypot(nan, nan)))
+        self.assertEqual(inf, math.hypot(inf, 4))
+        self.assertEqual(inf, math.hypot(4, inf))
+        self.assertEqual(inf, math.hypot(ninf, 4))
+        self.assertEqual(inf, math.hypot(4, ninf))
+
+
 def test_main():
     test_support.run_unittest(MathTestCase)
 

Modified: trunk/jython/src/org/python/compiler/Module.java
===================================================================
--- trunk/jython/src/org/python/compiler/Module.java	2011-03-30 15:17:27 UTC (rev 7277)
+++ trunk/jython/src/org/python/compiler/Module.java	2011-03-30 15:43:34 UTC (rev 7278)
@@ -72,7 +72,8 @@
 }
 
 class PyFloatConstant extends Constant implements ClassConstants, Opcodes {
-
+    private static final double ZERO = 0.0;
+    
     final double value;
 
     PyFloatConstant(double value) {
@@ -98,10 +99,14 @@
     @Override
     public boolean equals(Object o) {
         if (o instanceof PyFloatConstant) {
-            return ((PyFloatConstant) o).value == value;
-        } else {
-            return false;
+            double oVal = ((PyFloatConstant)o).value;
+            if (ZERO == value) {
+                // math.copysign() needs to distinguish signs of zeroes
+                return oVal == value && Double.toString(oVal).equals(Double.toString(value));
+            }
+            return oVal == value;
         }
+        return false;
     }
 }
 

Modified: trunk/jython/src/org/python/modules/math.java
===================================================================
--- trunk/jython/src/org/python/modules/math.java	2011-03-30 15:17:27 UTC (rev 7277)
+++ trunk/jython/src/org/python/modules/math.java	2011-03-30 15:43:34 UTC (rev 7278)
@@ -1,6 +1,8 @@
 // Copyright (c) Corporation for National Research Initiatives
 package org.python.modules;
 
+import java.math.BigInteger;
+
 import org.python.core.ClassDictInit;
 import org.python.core.Py;
 import org.python.core.PyFloat;
@@ -9,46 +11,127 @@
 import org.python.core.PyObject;
 import org.python.core.PyTuple;
 
+//
+// +++++ test the corner cases for every method again (e.g. test_math_jy.py)
+//
+
 public class math implements ClassDictInit {
     public static PyFloat pi = new PyFloat(Math.PI);
     public static PyFloat e = new PyFloat(Math.E);
+    
+    private static final double ZERO = 0.0;
+    private static final double MINUS_ZERO = -0.0;
+    private static final double HALF = 0.5;
+    private static final double ONE = 1.0;
+    private static final double MINUS_ONE = -1.0;
+    private static final double TWO = 2.0;
+    private static final double EIGHT = 8.0;
+    private static final double INF = Double.POSITIVE_INFINITY;
+    private static final double NINF = Double.NEGATIVE_INFINITY;
+    private static final double NAN = Double.NaN;
+    private static final BigInteger MAX_LONG_BIGINTEGER = new BigInteger(String.valueOf(Long.MAX_VALUE));
+    private static final BigInteger MIN_LONG_BIGINTEGER = new BigInteger(String.valueOf(Long.MIN_VALUE));
 
-    public static void classDictInit(PyObject dict) {
-    }
 
-    private static double check(double v) {
-        if (Double.isNaN(v))
-            throw Py.ValueError("math domain error");
-        if (Double.isInfinite(v))
-            throw Py.OverflowError("math range error");
-        return v;
+    public static void classDictInit(@SuppressWarnings("unused") PyObject dict) {
     }
 
     public static double acos(double v) {
-        return check(Math.acos(v));
+        if (isinf(v)) {
+            throwMathDomainValueError();
+        }
+        if (isnan(v)) {
+            return v;
+        }
+        return Math.acos(v);
     }
+    
+    public static double acosh(double v) {
+        if (isninf(v)) {
+            throwMathDomainValueError();
+        }
+        if (v == ZERO || v == MINUS_ONE) {
+            throwMathDomainValueError();
+        }
+        if (isnan(v) || isinf(v)) {
+            return v;
+        }
+        return log(v + sqrt(v * v - 1));
+    }
 
     public static double asin(double v) {
-        return check(Math.asin(v));
+        if (isinf(v)) {
+            throwMathDomainValueError();
+        }
+        if (isnan(v)) {
+            return v;
+        }
+        return Math.asin(v);
     }
+    
+    public static double asinh(double v) {
+        if (isnan(v) || isinf(v)) {
+            return v;
+        }
+        return log(v + sqrt(v * v + 1));
+    }
 
     public static double atan(double v) {
-        return check(Math.atan(v));
+        if (isnan(v)) {
+            return v;
+        }
+        return Math.atan(v);
     }
+    
+    public static double atanh(double v) {
+        if (isnan(v)) {
+            return v;
+        }
+        if (isinf(v) || Math.abs(v) == ONE) {
+            throwMathDomainValueError();
+        }
+        return log((1 + v) / (1 - v)) / 2;
+    }
 
     public static double atan2(double v, double w) {
-        return check(Math.atan2(v, w));
+        return Math.atan2(v, w);
     }
 
+    public static double ceil(PyObject v) {
+        return ceil(v.asDouble());
+    }
+
     public static double ceil(double v) {
-        return check(Math.ceil(v));
+        if (isnan(v) || isinf(v)) {
+            return v;
+        }
+        return Math.ceil(v);
     }
 
     public static double cos(double v) {
-        return check(Math.cos(v));
+        if (isnan(v) || isinf(v)) {
+            return NAN;
+        }
+        return Math.cos(v);
     }
 
+    public static double cosh(double v) {
+        if (isinf(v)) {
+            return INF;
+        }
+        if (isnan(v)) {
+            return v;
+        }
+        return HALF * (Math.exp(v) + Math.exp(-v));
+    }
+
     public static double exp(double v) {
+        if (isninf(v)) {
+            return ZERO;
+        }
+        if (isnan(v) || isinf(v)) {
+            return v;
+        }
         return check(Math.exp(v));
     }
 
@@ -57,7 +140,10 @@
     }
 
     public static double floor(double v) {
-        return check(Math.floor(v));
+        if (isnan(v) || isinf(v)) {
+            return v;
+        }
+        return Math.floor(v);
     }
 
     public static double log(PyObject v) {
@@ -77,37 +163,83 @@
         return doubleValue;
     }
 
-    private static double calculateLongLog(PyLong v) {
-        int e[] = new int[1];
-        double x = v.scaledDoubleValue(e);
-        if (x <= 0.0) throw Py.ValueError("math domain error");
-        return log(x) + (e[0]*8.0)*log(2.0);
-    }
-
-    private static double applyLoggedBase(double loggedValue, PyObject base) {
-        double loggedBase;
-        if (base instanceof PyLong) {
-            loggedBase = calculateLongLog((PyLong)base);
-        } else {
-            loggedBase = log(base.asDouble());
+    public static double pow(double v, double w) {
+        if (w == ZERO) {
+            return ONE;
         }
-        return check(loggedValue / loggedBase);
+        if (v == ONE) {
+            return v;
+        }
+        if (isnan(v) || isnan(w)) {
+            return NAN;
+        }
+        if (v == ZERO) {
+            if (w == ZERO) {
+                return ONE;
+            } else if (w > ZERO || ispinf(w)) {
+                return ZERO;
+            } else {
+                throwMathDomainValueError();
+            }
+        }
+        if (isninf(v)) {
+            if (isninf(w)) {
+                return ZERO;
+            }
+            if (isinf(w)) {
+                return INF;
+            }
+            if (w == ZERO) {
+                return ONE;
+            }
+            if (w > ZERO) {
+                if (isOdd(w)) {
+                    return NINF;
+                }
+                return INF;
+            }
+            if (isOdd(w)) {
+                return MINUS_ZERO;
+            }
+            return ZERO;
+        }
+        if (isninf(w)) {
+            if (v < ZERO) {
+                if (v == MINUS_ONE) {
+                    return ONE;
+                }
+                if (v < MINUS_ONE) {
+                    return ZERO;
+                }
+                return INF;
+            }
+        }
+        if (ispinf(w)) {
+            if (v < ZERO) {
+                if (v == MINUS_ONE) {
+                    return ONE;
+                }
+                if (v < MINUS_ONE) {
+                    return INF;
+                }
+                return ZERO;
+            }
+        }
+        if (v < ZERO && !isIntegral(w)) {
+            throwMathDomainValueError();
+        }
+        return Math.pow(v, w);
     }
 
-    private static double log(double v) {
-        return check(Math.log(v));
-    }
-
-    public static double pow(double v, double w) {
-        return check(Math.pow(v, w));
-    }
-
     public static double sin(PyObject v) {
         return sin(v.asDouble());
     }
 
     public static double sin(double v) {
-        return check(Math.sin(v));
+        if (isnan(v)) {
+            return v;
+        }
+        return Math.sin(v);
     }
 
     public static double sqrt(PyObject v) {
@@ -115,37 +247,61 @@
     }
 
     public static double sqrt(double v) {
-        return check(Math.sqrt(v));
+        if (isnan(v)) {
+            return v;
+        }
+        if (ispinf(v)) {
+            return v;
+        }
+        if (isninf(v) || v == MINUS_ONE) {
+            throwMathDomainValueError();
+        }
+        return Math.sqrt(v);
     }
 
     public static double tan(double v) {
-        return check(Math.tan(v));
+        if (isnan(v) || isinf(v)) {
+            return NAN;
+        }
+        return Math.tan(v);
     }
 
     public static double log10(PyObject v) {
         if (v instanceof PyLong) {
-            int e[] = new int[1];
-            double x = ((PyLong)v).scaledDoubleValue(e);
-            if (x <= 0.0) throw Py.ValueError("math domain error");
-            return log10(x) + (e[0]*8.0)*log10(2.0);
+            int exp[] = new int[1];
+            double x = ((PyLong)v).scaledDoubleValue(exp);
+            if (x <= ZERO) {
+                throwMathDomainValueError();
+            }
+            return log10(x) + (exp[0] * EIGHT) * log10(TWO);
         }
         return log10(v.asDouble());
     }
 
-    private static double log10(double v) {
-        return check(Math.log10(v));
-    }
-
     public static double sinh(double v) {
-        return check(0.5 * (Math.exp(v) - Math.exp(-v)));
+        if (isnan(v)) {
+            return v;
+        }
+        if (isinf(v)) {
+            return v;
+        }
+        return HALF * (Math.exp(v) - Math.exp(-v));
     }
 
-    public static double cosh(double v) {
-        return check(0.5 * (Math.exp(v) + Math.exp(-v)));
-    }
-
     public static double tanh(double v) {
-        return check(sinh(v) / cosh(v));
+        if (isnan(v)) {
+            return v;
+        }
+        if (isinf(v)) {
+            if (isninf(v)) {
+                return MINUS_ONE;
+            }
+            return ONE;
+        }
+        if (v == MINUS_ZERO) {
+            return v;
+        }
+        return sinh(v) / cosh(v);
     }
 
     public static double fabs(double v) {
@@ -153,11 +309,33 @@
     }
 
     public static double fmod(double v, double w) {
+        if (isnan(v) || isnan(w)) {
+            return NAN;
+        }
+        if (isinf(w)) {
+            return v;
+        }
+        if (w == ZERO) {
+            throwMathDomainValueError();
+        }
+        if (isinf(v) && w == ONE) {
+            throwMathDomainValueError();
+        }
         return v % w;
     }
 
     public static PyTuple modf(double v) {
-        double w = v % 1.0;
+        if (isnan(v)) {
+            return new PyTuple(new PyFloat(v), new PyFloat(v));
+        }
+        if (isinf(v)) {
+            double first = ZERO;
+            if (isninf(v)) {
+                first = MINUS_ZERO;
+            }
+            return new PyTuple(new PyFloat(first), new PyFloat(v));
+        }
+        double w = v % ONE;
         v -= w;
         return new PyTuple(new PyFloat(w), new PyFloat(v));
     }
@@ -165,39 +343,228 @@
     public static PyTuple frexp(double x) {
         int exponent = 0;
 
-        if (Double.isNaN(x) || Double.isInfinite(x) || x == 0.0) {
+        if (isnan(x) || isinf(x) || x == ZERO) {
             exponent = 0;
         } else {
             short sign = 1;
 
-            if (x < 0.0) {
+            if (x < ZERO) {
                 x = -x;
                 sign = -1;
             }
+            
+            for (; x < HALF; x *= TWO, exponent--); // needs an empty statement
 
-            for (; x < 0.5; x *= 2.0, exponent--);
+            for (; x >= ONE; x *= HALF, exponent++); // needs an empty statement
 
-            for (; x >= 1.0; x *= 0.5, exponent++);
-
             x *= sign;
         }
         return new PyTuple(new PyFloat(x), new PyInteger(exponent));
     }
 
     public static double ldexp(double v, PyObject wObj) {
-        int w = wObj.asInt();
-        return check(v * Math.pow(2.0, w));
+        if (ZERO == v) {
+            return v; // can be negative zero
+        }
+        if (isinf(v)) {
+            return v;
+        }
+        if (isnan(v)) {
+            return v;
+        }
+        long w = getLong(wObj);
+        if (w == Long.MIN_VALUE) {
+            if (v > ZERO) {
+                return ZERO;
+            }
+            return MINUS_ZERO;
+        }
+        return checkOverflow(v * Math.pow(TWO, w));
     }
 
     public static double hypot(double v, double w) {
-        return check(Math.hypot(v, w));
+        if (isinf(v) || isinf(w)) {
+            return INF;
+        }
+        if (isnan(v) || isnan(w)) {
+            return NAN;
+        }
+        return Math.hypot(v, w);
     }
 
     public static double radians(double v) {
-    	return check(Math.toRadians(v));
+        return check(Math.toRadians(v));
     }
 
     public static double degrees(double v) {
-    	return check(Math.toDegrees(v));
+        return check(Math.toDegrees(v));
     }
+    
+    public static boolean isnan(double v) {
+        return Double.isNaN(v);
+    }
+    
+    /**
+     * @param v
+     * 
+     * @return <code>true</code> if v is positive or negative infinity
+     */
+    public static boolean isinf(double v) {
+        return Double.isInfinite(v);
+    }
+    
+    public static double copysign(double v, double w) {
+        if (isnan(v)) {
+            return NAN;
+        }
+        if (signum(v) == signum(w)) {
+            return v;
+        }
+        return v *= MINUS_ONE;
+    }
+    
+    public static PyLong factorial(double v) {
+        if (v == ZERO || v == ONE) {
+            return new PyLong(1);
+        }
+        if (v < ZERO || isnan(v) || isinf(v)) {
+            throwMathDomainValueError();
+        }
+        if (!isIntegral(v)) {
+            throwMathDomainValueError();
+        }
+        // long input should be big enough :-)
+        long value = (long)v;
+        BigInteger bi = new BigInteger(Long.toString(value));
+        for (long l = value - 1; l > 1; l--) {
+            bi = bi.multiply(new BigInteger(Long.toString(l)));
+        }
+        return new PyLong(bi);
+    }
+
+    public static double log1p(double v) {
+        return log(ONE + v);
+    }
+    
+    public static double fsum(double... values) {
+        // TODO need an iterable
+        // TODO need sys.float_info
+        return 0;
+    }
+
+    private static double calculateLongLog(PyLong v) {
+        int exp[] = new int[1];
+        double x = v.scaledDoubleValue(exp);
+        if (x <= ZERO) {
+            throwMathDomainValueError();
+        }
+        return log(x) + (exp[0] * EIGHT) * log(TWO);
+    }
+
+    private static double applyLoggedBase(double loggedValue, PyObject base) {
+        double loggedBase;
+        if (base instanceof PyLong) {
+            loggedBase = calculateLongLog((PyLong)base);
+        } else {
+            loggedBase = log(base.asDouble());
+        }
+        return check(loggedValue / loggedBase);
+    }
+
+    private static double log(double v) {
+        if (isninf(v)) {
+            throwMathDomainValueError();
+        }
+        if (isinf(v) || isnan(v)) {
+            return v;
+        }
+        return Math.log(v);
+    }
+
+    private static double log10(double v) {
+        if (isninf(v)) {
+            throwMathDomainValueError();
+        }
+        if (isinf(v) || isnan(v)) {
+            return v;
+        }
+        return Math.log10(v);
+    }
+    
+    private static boolean isninf(double v) {
+        return v == NINF;
+    }
+
+    private static boolean ispinf(double v) {
+        return v == INF;
+    }
+    
+    /**
+     * work around special Math.signum() behaviour for positive and negative zero
+     */
+    private static double signum(double v) {
+        double signum = ONE;
+        if (v == ZERO) {
+            if ('-' == Double.toString(v).charAt(0)) {
+                signum = MINUS_ONE;
+            }
+        } else {
+            signum = Math.signum(v);
+        }
+        return signum;
+    }
+
+    private static void throwMathDomainValueError() {
+        throw Py.ValueError("math domain error");
+    }
+
+    private static double check(double v) {
+        if (isnan(v))
+            throwMathDomainValueError();
+        if (isinf(v))
+            throw Py.OverflowError("math range error");
+        return v;
+    }
+    
+    private static double checkOverflow(double v) {
+        if (isinf(v)) {
+            throw Py.OverflowError("math range error");
+        }
+        return v;
+    }
+    
+    /**
+     * convert a PyObject into a long between Long.MIN_VALUE and Long.MAX_VALUE
+     */
+    private static long getLong(PyObject pyo) {
+        if (pyo instanceof PyLong) {
+            return getLong(((PyLong)pyo));
+        }
+        return pyo.asLong();
+    }
+    
+    /**
+     * convert a PyLong into a long between Long.MIN_VALUE and Long.MAX_VALUE
+     */
+    private static long getLong(PyLong pyLong) {
+        BigInteger value = pyLong.getValue();
+        if (value.compareTo(MAX_LONG_BIGINTEGER) > 0) {
+            return Long.MAX_VALUE;
+        }
+        if (value.compareTo(MIN_LONG_BIGINTEGER) < 0) {
+            return Long.MIN_VALUE;
+        }
+        return value.longValue();
+    }
+    
+    
+    private static boolean isIntegral(double v) {
+        return ceil(v) - v == ZERO;
+    }
+
+    
+    private static boolean isOdd(double v) {
+        return isIntegral(v) && v % TWO != ZERO;
+    }
+
 }

Added: trunk/jython/tests/java/org/python/compiler/ModuleTest.java
===================================================================
--- trunk/jython/tests/java/org/python/compiler/ModuleTest.java	                        (rev 0)
+++ trunk/jython/tests/java/org/python/compiler/ModuleTest.java	2011-03-30 15:43:34 UTC (rev 7278)
@@ -0,0 +1,21 @@
+package org.python.compiler;
+
+import junit.framework.TestCase;
+
+public class ModuleTest extends TestCase {
+
+    /**
+     * In order to get testCopysign() in test_math.py passing, PyFloatConstant needs to distinguish
+     * between 0.0 and -0.0:
+     * 
+     * <pre>
+     *   # copysign should let us distinguish signs of zeros
+     * </pre>
+     */
+    public void testPyFloatConstant_Zero() {
+        PyFloatConstant positiveZero = new PyFloatConstant(0.0);
+        PyFloatConstant negativeZero = new PyFloatConstant(-0.0);
+        assertNotSame(positiveZero, negativeZero);
+        assertFalse(positiveZero.equals(negativeZero));
+    }
+}

Added: trunk/jython/tests/java/org/python/core/PyFloatTest.java
===================================================================
--- trunk/jython/tests/java/org/python/core/PyFloatTest.java	                        (rev 0)
+++ trunk/jython/tests/java/org/python/core/PyFloatTest.java	2011-03-30 15:43:34 UTC (rev 7278)
@@ -0,0 +1,63 @@
+package org.python.core;
+
+import junit.framework.TestCase;
+
+public class PyFloatTest extends TestCase {
+
+    private final static double nan = Double.NaN;
+
+    private final static double inf = Double.POSITIVE_INFINITY;
+
+    private final static double ninf = Double.NEGATIVE_INFINITY;
+
+    /**
+     * test the basic behavior of java.lang.Double extreme values
+     */
+    public void test_Double_InfinityAndNaN() {
+        assertTrue(Double.NaN != nan); // this is the definition of NaN
+        assertTrue(Double.isNaN(nan));
+        assertFalse(Double.isInfinite(nan));
+        assertTrue(Double.POSITIVE_INFINITY == inf);
+        assertFalse(Double.isNaN(inf));
+        assertTrue(Double.isInfinite(inf));
+        assertTrue(Double.NEGATIVE_INFINITY == ninf);
+        assertFalse(Double.isNaN(ninf));
+        assertTrue(Double.isInfinite(ninf));
+        assertTrue(nan != inf);
+        assertTrue(nan != ninf);
+        assertTrue(inf != ninf);
+    }
+
+    /**
+     * test extreme values
+     */
+    public void testInfinityAndNaN() {
+        PyFloat fNan = new PyFloat(Double.NaN);
+        PyFloat fInf = new PyFloat(Double.POSITIVE_INFINITY);
+        PyFloat fNinf = new PyFloat(Double.NEGATIVE_INFINITY);
+        assertTrue(Double.NaN != fNan.getValue()); // this is the definition of NaN
+        assertTrue(Double.isNaN(fNan.getValue()));
+        assertFalse(Double.isInfinite(fNan.getValue()));
+        assertTrue(Double.POSITIVE_INFINITY == fInf.getValue());
+        assertFalse(Double.isNaN(fInf.getValue()));
+        assertTrue(Double.isInfinite(fInf.getValue()));
+        assertTrue(Double.NEGATIVE_INFINITY == fNinf.getValue());
+        assertFalse(Double.isNaN(fNinf.getValue()));
+        assertTrue(Double.isInfinite(fNinf.getValue()));
+        assertTrue(fNan.getValue() != fInf.getValue());
+        assertTrue(fNan.getValue() != fNinf.getValue());
+        assertTrue(fInf.getValue() != fNinf.getValue());
+    }
+
+    /**
+     * test formatting of extreme values
+     */
+    public void testInfinityAndNaN_repr() {
+        PyFloat fNan = new PyFloat(Double.NaN);
+        PyFloat fInf = new PyFloat(Double.POSITIVE_INFINITY);
+        PyFloat fNinf = new PyFloat(Double.NEGATIVE_INFINITY);
+        assertEquals("nan", String.valueOf(fNan.__repr__()));
+        assertEquals("inf", String.valueOf(fInf.__repr__()));
+        assertEquals("-inf", String.valueOf(fNinf.__repr__()));
+    }
+}


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.

------------------------------------------------------------------------------
Create and publish websites with WebMatrix
Use the most popular FREE web apps or write code yourself; 
WebMatrix provides all the features you need to develop and 
publish your website. http://p.sf.net/sfu/ms-webmatrix-sf