[pypy-svn] r16019 - pypy/dist/pypy/objspace/std

tismer at codespeak.net tismer at codespeak.net
Fri Aug 12 20:33:03 CEST 2005


Author: tismer
Date: Fri Aug 12 20:33:01 2005
New Revision: 16019

Modified:
   pypy/dist/pypy/objspace/std/floattype.py
   pypy/dist/pypy/objspace/std/strutil.py
Log:
reimplementation of string_to_float at interp level.
Changed floattype to use this.

This is intermediate, interp_string_to_float will get the
old (spaceless) interface back after factoring the
long implementation out of longobject.


Modified: pypy/dist/pypy/objspace/std/floattype.py
==============================================================================
--- pypy/dist/pypy/objspace/std/floattype.py	(original)
+++ pypy/dist/pypy/objspace/std/floattype.py	Fri Aug 12 20:33:01 2005
@@ -1,6 +1,9 @@
 from pypy.objspace.std.stdtypedef import *
 from pypy.interpreter.error import OperationError
 from pypy.objspace.std.strutil import string_to_float, ParseStringError
+from pypy.objspace.std.strutil import interp_string_to_float
+
+USE_NEW_S2F = True
 
 def descr__new__(space, w_floattype, w_x=0.0):
     from pypy.objspace.std.floatobject import W_FloatObject
@@ -8,19 +11,21 @@
     if space.is_true(space.isinstance(w_value, space.w_str)):
         strvalue = space.str_w(w_value)
         try:
-            value = string_to_float(strvalue)
+            if USE_NEW_S2F:
+                value = interp_string_to_float(space, strvalue)
+            else:
+                value = string_to_float(strvalue)
         except ParseStringError, e:
             raise OperationError(space.w_ValueError,
                                  space.wrap(e.msg))
-        except OverflowError, e:
-            # this should not happen, but if it does, catch it!
-            raise OperationError(space.w_OverflowError,
-                                 space.wrap(str(e)))
     elif space.is_true(space.isinstance(w_value, space.w_unicode)):
         from unicodeobject import unicode_to_decimal_w
         strvalue = unicode_to_decimal_w(space, w_value)
         try:
-            value = string_to_float(strvalue)
+            if USE_NEW_S2F:
+                value = interp_string_to_float(space, strvalue)
+            else:
+                value = string_to_float(strvalue)
         except ParseStringError, e:
             raise OperationError(space.w_ValueError,
                                  space.wrap(e.msg))

Modified: pypy/dist/pypy/objspace/std/strutil.py
==============================================================================
--- pypy/dist/pypy/objspace/std/strutil.py	(original)
+++ pypy/dist/pypy/objspace/std/strutil.py	Fri Aug 12 20:33:01 2005
@@ -3,7 +3,7 @@
 """
 
 from pypy.rpython.rarithmetic import r_uint, ovfcheck, ovfcheck_float_to_int, parts_to_float
-
+from pypy.interpreter.error import OperationError
 import math
 
 # XXX factor more functions out of stringobject.py.
@@ -293,14 +293,14 @@
     # 1) parse the string into pieces.
     sign, before_point, after_point, exponent = break_up_float(s)
     
-    if not before_point and not after_point:
+    digits = before_point + after_point
+    if digits:
         raise ParseStringError("invalid literal for float()")
 
     # 2) pre-calculate digit exponent dexp.
     dexp = len(before_point)
 
     # 3) truncate and adjust dexp.
-    digits = before_point + after_point
     p = 0
     plim = dexp + len(after_point)
     while p < plim and digits[p] == '0':
@@ -362,3 +362,124 @@
         r = -r
 
     return r
+
+
+# the "real" implementation.
+# for comments, see above.
+# XXX probably this very specific thing should go into longobject?
+
+def interp_string_to_float(space, s):
+    """
+    Conversion of string to float.
+    This version tries to only raise on invalid literals.
+    Overflows should be converted to infinity whenever possible.
+
+    Expects an unwrapped string and return an unwrapped float.
+    """
+
+    if not s:
+        raise OperationError(space.w_ValueError, space.wrap(
+            "empty string for float()"))
+
+    # 1) parse the string into pieces.
+    sign, before_point, after_point, exponent = break_up_float(s)
+    
+    digits = before_point + after_point
+    if not digits:
+        raise ParseStringError("invalid literal for float()")
+
+    # 2) pre-calculate digit exponent dexp.
+    dexp = len(before_point)
+
+    # 3) truncate and adjust dexp.
+    p = 0
+    plim = dexp + len(after_point)
+    while p < plim and digits[p] == '0':
+        p += 1
+        dexp -= 1
+    digits = digits[p : p + MANTISSA_DIGITS]
+    p = len(digits) - 1
+    while p >= 0 and digits[p] == '0':
+        p -= 1
+    dexp -= p + 1
+    p += 1
+    assert p >= 0
+    digits = digits[:p]
+    if len(digits) == 0:
+        digits = '0'
+
+    # a few abbreviations
+    from pypy.objspace.std import longobject
+    mklong = longobject.W_LongObject.fromint
+    d2long = longobject._decimalstr_to_long
+    adlong = longobject.add__Long_Long
+    long2i = longobject._AsLong
+    double = longobject._AsDouble
+    longup = longobject._impl_long_long_pow
+    multip = longobject.mul__Long_Long
+    divide = longobject.div__Long_Long
+    bitlen = longobject._count_bits
+    lshift = longobject.lshift__Long_Long
+    rshift = longobject.rshift__Long_Long
+    getodd = longobject._get_odd
+
+    # 4) compute the exponent and truncate to +-400
+    if not exponent:
+        exponent = '0'
+    w_le = d2long(space, exponent)
+    w_le = adlong(space, w_le, mklong(space, dexp))
+    try:
+        e = long2i(w_le)
+    except OverflowError:
+        e = w_le.sign * 400
+    if e >= 400:
+        e = 400
+    elif e <= -400:
+        e = -400
+
+    # 5) compute the value using long math and proper rounding.
+    w_lr = d2long(space, digits)
+    w_10 = mklong(space, 10)
+    w_1 = mklong(space, 1)
+    if e >= 0:
+        bits = 0
+        w_pten = longup(space, w_10, mklong(space, e), None)
+        w_m = multip(space, w_lr, w_pten)
+    else:
+        # compute a sufficiently large scale
+        prec = MANTISSA_DIGITS * 2 + 22 # 128, maybe
+        bits = - (int(math.ceil(-e / math.log10(2) - 1e-10)) + prec)
+        w_scale = lshift(space, w_1, mklong(space, -bits))
+        w_pten = longup(space, w_10, mklong(space, -e), None)
+        w_tmp = multip(space, w_lr, w_scale)
+        w_m = divide(space, w_tmp, w_pten)
+
+    # we now have a fairly large mantissa.
+    # Shift it and round the last bit.
+
+    # first estimate the bits and do a big shift
+    mbits = bitlen(w_m)
+    needed = MANTISSA_BITS
+    if mbits > needed:
+        if mbits > needed+1:
+            shifted = mbits - (needed+1)
+            w_m = rshift(space, w_m, mklong(space, shifted))
+            bits += shifted
+        # do the rounding
+        bits += 1
+        round = getodd(w_m)
+        w_m = rshift(space, w_m, w_1)
+        w_m = adlong(space, w_m, mklong(space, round))
+
+    try:
+        r = math.ldexp(double(w_m), bits)
+        # XXX I guess we do not check for overflow in ldexp as we agreed to!
+        if r == 2*r and r != 0.0:
+            raise OverflowError
+    except OverflowError:
+        r = 1e200 * 1e200 # produce inf, hopefully
+
+    if sign == '-':
+        r = -r
+
+    return r



More information about the Pypy-commit mailing list