[pypy-svn] r16410 - in pypy/dist/pypy: module/math objspace/std rpython/module/test

tismer at codespeak.net tismer at codespeak.net
Wed Aug 24 18:26:12 CEST 2005


Author: tismer
Date: Wed Aug 24 18:26:08 2005
New Revision: 16410

Modified:
   pypy/dist/pypy/module/math/__init__.py
   pypy/dist/pypy/module/math/interp_math.py
   pypy/dist/pypy/objspace/std/longobject.py
   pypy/dist/pypy/rpython/module/test/test_ll_math.py
Log:
added a complete implementation of log/log10

Modified: pypy/dist/pypy/module/math/__init__.py
==============================================================================
--- pypy/dist/pypy/module/math/__init__.py	(original)
+++ pypy/dist/pypy/module/math/__init__.py	Wed Aug 24 18:26:08 2005
@@ -18,7 +18,6 @@
        'hypot'          : 'interp_math.hypot',
        'tan'            : 'interp_math.tan',
        'asin'           : 'interp_math.asin',
-       'log'            : 'interp_math.log',
        'fabs'           : 'interp_math.fabs',
        'floor'          : 'interp_math.floor',
        'sqrt'           : 'interp_math.sqrt',

Modified: pypy/dist/pypy/module/math/interp_math.py
==============================================================================
--- pypy/dist/pypy/module/math/interp_math.py	(original)
+++ pypy/dist/pypy/module/math/interp_math.py	Wed Aug 24 18:26:08 2005
@@ -2,6 +2,7 @@
 import math
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.gateway import ObjSpace, W_Root, NoneNotWrapped
+from pypy.objspace.std import longobject
 
 class State: 
     def __init__(self, space): 
@@ -44,9 +45,9 @@
         raise OperationError(space.w_ValueError,
                              space.wrap("math domain error"))
     return space.wrap(r)
-math2._annspecialcase_ = 'specialize:arg1'    
+math2._annspecialcase_ = 'specialize:arg1'
 
-def pow(space, x, y):                     
+def pow(space, x, y):
     """pow(x,y)
        
        Return x**y (x to the power of y).
@@ -92,18 +93,6 @@
     return math1(space, math.asin, x)
 asin.unwrap_spec = [ObjSpace, float]
 
-def log(space, x,  w_base=NoneNotWrapped):
-    """log(x[, base]) -> the logarithm of x to the given base.
-       If the base not specified, returns the natural logarithm (base e) of x.
-    """
-    num = math1_w(space, math.log, x) 
-    if w_base is None:
-        return space.wrap(num)
-    else:
-        den = math1_w(space, math.log, space.float_w(w_base))
-        return space.wrap(num / den)
-log.unwrap_spec = [ObjSpace, float, W_Root]
-
 def fabs(space, x): 
     """fabs(x)
        
@@ -148,11 +137,65 @@
     return space.wrap(x / degToRad)
 degrees.unwrap_spec = [ObjSpace, float]
 
-def log10(space, x): 
-    """log10(x) -> the base 10 logarithm of x.
+def _log_float(space, x, base):
+    if base == 10.0:
+        return math1(space, math.log10, x)
+    num = math1_w(space, math.log, x) 
+    if base == 0.0:
+        return space.wrap(num)
+    else:
+        den = math1_w(space, math.log, base)
+        return space.wrap(num / den)
+
+def _log_any(space, w_x, base):
+    try:
+        x = space.float_w(w_x)
+    except OperationError:
+        pass
+    else:
+        return _log_float(space, x, base)
+    try:
+        w_x = space.long(w_x)
+    except OperationError:
+        raise OperationError(space.w_TypeError, space.wrap(
+            'a float is required')) # yes, this message is as bad as CPython's
+    try:
+        if base == 10.0:
+            return space.wrap(longobject._loghelper(math.log10, w_x))
+        ret = longobject._loghelper(math.log, w_x)
+        if base != 0.0:
+            ret /= math.log(base)
+        return space.wrap(ret)
+    except OverflowError:
+        raise OperationError(space.w_OverflowError,
+                             space.wrap("math range error"))
+    except ValueError:
+        raise OperationError(space.w_ValueError,
+                             space.wrap("math domain error"))
+
+def log(space, w_x, w_base=NoneNotWrapped):
+    """log(x[, base]) -> the logarithm of x to the given base.
+       If the base not specified, returns the natural logarithm (base e) of x.
     """
-    return math1(space, math.log10, x)
-log10.unwrap_spec = [ObjSpace, float]
+    if w_base is None:
+        base = 0.0
+    else:
+        try:
+            base = space.float_w(w_base)
+        except OperationError:
+            raise OperationError(space.w_TypeError, space.wrap(
+                'a float is required'))
+        if base <= 0.0:
+            # just for raising the proper errors
+            return math1(space, math.log, base)
+    return _log_any(space, w_x, base)
+log.unwrap_spec = [ObjSpace, W_Root, W_Root]
+
+def log10(space, w_x): 
+    """log10(x) -> the base 10 logarithm of x.
+    """ 
+    return _log_any(space, w_x, 10.0)
+log10.unwrap_spec = [ObjSpace, W_Root]
 
 def fmod(space, x, y): 
     """fmod(x,y)

Modified: pypy/dist/pypy/objspace/std/longobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/longobject.py	(original)
+++ pypy/dist/pypy/objspace/std/longobject.py	Wed Aug 24 18:26:08 2005
@@ -1260,6 +1260,7 @@
 # note that math.ldexp checks for overflows,
 # while the C ldexp is not guaranteed to do.
 # XXX make sure that we don't ignore this!
+# YYY no, we decided to do ignore this!
 
 def _AsDouble(v):
     """ Get a C double from a long int object. """
@@ -1271,6 +1272,23 @@
         return x
     raise OverflowError # can't say "long int too large to convert to float"
 
+def _loghelper(func, w_arg):
+    """
+    A decent logarithm is easy to compute even for huge longs, but libm can't
+    do that by itself -- loghelper can.  func is log or log10, and name is
+    "log" or "log10".  Note that overflow isn't possible:  a long can contain
+    no more than INT_MAX * SHIFT bits, so has value certainly less than
+    2**(2**64 * 2**16) == 2**2**80, and log2 of that is 2**80, which is
+    small enough to fit in an IEEE single.  log and log10 are even smaller.
+    """
+    x, e = _AsScaledDouble(w_arg);
+    # Value is ~= x * 2**(e*SHIFT), so the log ~=
+    # log(x) + log(2) * e * SHIFT.
+    # CAUTION:  e*SHIFT may overflow using int arithmetic,
+    # so force use of double. */
+    return func(x) + (e * float(SHIFT) * func(2.0))
+_loghelper._annspecialcase_ = 'specialize:arg0'
+
 def _long_true_divide(a, b):
     try:
         ad, aexp = _AsScaledDouble(a)

Modified: pypy/dist/pypy/rpython/module/test/test_ll_math.py
==============================================================================
--- pypy/dist/pypy/rpython/module/test/test_ll_math.py	(original)
+++ pypy/dist/pypy/rpython/module/test/test_ll_math.py	Wed Aug 24 18:26:08 2005
@@ -19,6 +19,8 @@
 def test_ll_log():
     assert ll_math_log(8943.790148912) == math.log(8943.790148912)
     assert ll_math_log10(8943.790148912) == math.log10(8943.790148912)
+    assert ll_math_log(1L << 10000) == math.log(1L << 10000)
+    assert ll_math_log10(1L << 10000) == math.log10(1L << 10000)
 
 def test_ll_cos_sin():
     assert ll_math_cos(math.pi/3) == math.cos(math.pi/3)



More information about the Pypy-commit mailing list