[pypy-svn] pypy shorter-float-repr: Move the dtoa wrappers to pypy/rlib/

amauryfa commits-noreply at bitbucket.org
Fri Jan 21 14:42:41 CET 2011


Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: shorter-float-repr
Changeset: r41130:9d4d6ccbd1b1
Date: 2011-01-21 14:39 +0100
http://bitbucket.org/pypy/pypy/changeset/9d4d6ccbd1b1/

Log:	Move the dtoa wrappers to pypy/rlib/ Let's see how this
	translates...

diff --git a/pypy/rpython/module/ll_strtod.py b/pypy/rpython/module/ll_strtod.py
--- a/pypy/rpython/module/ll_strtod.py
+++ b/pypy/rpython/module/ll_strtod.py
@@ -9,8 +9,6 @@
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
 from pypy.tool.autopath import pypydir
 
-USE_DTOA = True # XXX make it a translation option
-
 class CConfig:
     _compilation_info_ = ExternalCompilationInfo(
         includes = ['src/ll_strtod.h'],
@@ -61,10 +59,6 @@
 
             return s
 
-        if USE_DTOA:
-            from pypy.rpython.module.ll_dtoa import llimpl_strtod
-            llimpl = llimpl_strtod
-
         def oofakeimpl(x, code, precision, flags):
             return ootype.oostring(rarithmetic.formatd(x, code, precision, flags), -1)
 

diff --git a/pypy/rpython/module/ll_dtoa.py b/pypy/rpython/module/ll_dtoa.py
deleted file mode 100644
--- a/pypy/rpython/module/ll_dtoa.py
+++ /dev/null
@@ -1,245 +0,0 @@
-from __future__ import with_statement
-from pypy.rlib import rarithmetic
-from pypy.translator.tool.cbuild import ExternalCompilationInfo
-from pypy.tool.autopath import pypydir
-from pypy.rpython.lltypesystem import lltype, rffi
-from pypy.rlib.rstring import StringBuilder
-import py
-
-cdir = py.path.local(pypydir) / 'translator' / 'c'
-include_dirs = [cdir]
-
-eci = ExternalCompilationInfo(
-    include_dirs = [cdir],
-    libraries = [],
-    separate_module_files = [cdir / 'src' / 'dtoa.c'],
-    separate_module_sources = ['''
-       #include <stdlib.h>
-       #include <assert.h>
-       #include "src/allocator.h"
-    '''],
-    export_symbols = ['_PyPy_dg_strtod',
-                      '_PyPy_dg_dtoa',
-                      '_PyPy_dg_freedtoa',
-                      ],
-    )
-
-dg_strtod = rffi.llexternal(
-    '_PyPy_dg_strtod', [rffi.CCHARP, rffi.CCHARPP], rffi.DOUBLE,
-    compilation_info=eci)
-
-dg_dtoa = rffi.llexternal(
-    '_PyPy_dg_dtoa', [rffi.DOUBLE, rffi.INT, rffi.INT,
-                    rffi.INTP, rffi.INTP, rffi.CCHARPP], rffi.CCHARP,
-    compilation_info=eci)
-
-dg_freedtoa = rffi.llexternal(
-    '_PyPy_dg_freedtoa', [rffi.CCHARP], lltype.Void,
-    compilation_info=eci)
-
-def strtod(input):
-    with lltype.scoped_alloc(rffi.CCHARPP.TO, 1) as end_ptr:
-        with rffi.scoped_str2charp(input) as ll_input:
-            result = dg_strtod(ll_input, end_ptr)
-            if end_ptr[0] and ord(end_ptr[0][0]):
-                offset = (rffi.cast(rffi.LONG, end_ptr[0]) -
-                          rffi.cast(rffi.LONG, ll_input))
-                raise ValueError("invalid input at position %d" % (offset,))
-            return result
-
-def format_nonfinite(digits, sign, flags):
-    "Format dtoa's output for nonfinite numbers"
-    if digits[0] == 'i' or digits[0] == 'I':
-        if sign == 1:
-            return '-inf'
-        elif flags & rarithmetic.DTSF_SIGN:
-            return '+inf'
-        else:
-            return 'inf'
-    elif digits[0] == 'n' or digits[0] == 'N':
-        return 'nan'
-    else:
-        # shouldn't get here
-        raise ValueError
-
-def format_number(digits, buflen, sign, decpt, code, precision, flags):
-    # We got digits back, format them.  We may need to pad 'digits'
-    # either on the left or right (or both) with extra zeros, so in
-    # general the resulting string has the form
-    #
-    # [<sign>]<zeros><digits><zeros>[<exponent>]
-    #
-    # where either of the <zeros> pieces could be empty, and there's a
-    # decimal point that could appear either in <digits> or in the
-    # leading or trailing <zeros>.
-    #
-    # Imagine an infinite 'virtual' string vdigits, consisting of the
-    # string 'digits' (starting at index 0) padded on both the left
-    # and right with infinite strings of zeros.  We want to output a
-    # slice
-    #
-    # vdigits[vdigits_start : vdigits_end]
-    #
-    # of this virtual string.  Thus if vdigits_start < 0 then we'll
-    # end up producing some leading zeros; if vdigits_end > digits_len
-    # there will be trailing zeros in the output.  The next section of
-    # code determines whether to use an exponent or not, figures out
-    # the position 'decpt' of the decimal point, and computes
-    # 'vdigits_start' and 'vdigits_end'.
-    builder = StringBuilder(20)
-
-    use_exp = False
-    vdigits_end = buflen
-    if code == 'e':
-        use_exp = True
-        vdigits_end = precision
-    elif code == 'f':
-        vdigits_end = decpt + precision
-    elif code == 'g':
-        if decpt <= -4:
-            use_exp = True
-        elif decpt > precision:
-            use_exp = True
-        elif flags & rarithmetic.DTSF_ADD_DOT_0 and decpt == precision:
-            use_exp = True
-        if flags & rarithmetic.DTSF_ALT:
-            vdigits_end = precision
-    elif code == 'r':
-        #  convert to exponential format at 1e16.  We used to convert
-        #  at 1e17, but that gives odd-looking results for some values
-        #  when a 16-digit 'shortest' repr is padded with bogus zeros.
-        #  For example, repr(2e16+8) would give 20000000000000010.0;
-        #  the true value is 20000000000000008.0.
-        if decpt <= -4 or decpt > 16:
-            use_exp = True
-    else:
-        raise ValueError
-
-    # if using an exponent, reset decimal point position to 1 and
-    # adjust exponent accordingly.
-    if use_exp:
-        exp = decpt - 1
-        decpt = 1
-    else:
-        exp = 0
-
-    # ensure vdigits_start < decpt <= vdigits_end, or vdigits_start <
-    # decpt < vdigits_end if add_dot_0_if_integer and no exponent
-    if decpt <= 0:
-        vdigits_start = decpt-1
-    else:
-        vdigits_start = 0
-    if vdigits_end <= decpt:
-        if not use_exp and flags & rarithmetic.DTSF_ADD_DOT_0:
-            vdigits_end = decpt + 1
-        else:
-            vdigits_end = decpt
-
-    # double check inequalities
-    assert vdigits_start <= 0
-    assert 0 <= buflen <= vdigits_end
-    # decimal point should be in (vdigits_start, vdigits_end]
-    assert vdigits_start < decpt <= vdigits_end
-
-    if sign == 1:
-        builder.append('-')
-    elif flags & rarithmetic.DTSF_SIGN:
-        builder.append('+')
-
-    # note that exactly one of the three 'if' conditions is true, so
-    # we include exactly one decimal point
-    # 1. Zero padding on left of digit string
-    if decpt <= 0:
-        builder.append_multiple_char('0', decpt - vdigits_start)
-        builder.append('.')
-        builder.append_multiple_char('0', 0 - decpt)
-    else:
-        builder.append_multiple_char('0', 0 - vdigits_start)
-
-    # 2. Digits, with included decimal point
-    if 0 < decpt <= buflen:
-        builder.append(rffi.charpsize2str(digits, decpt - 0))
-        builder.append('.')
-        ptr = rffi.ptradd(digits, decpt)
-        builder.append(rffi.charpsize2str(ptr, buflen - decpt))
-    else:
-        builder.append(rffi.charpsize2str(digits, buflen))
-
-    # 3. And zeros on the right
-    if buflen < decpt:
-        builder.append_multiple_char('0', decpt - buflen)
-        builder.append('.')
-        builder.append_multiple_char('0', vdigits_end - decpt)
-    else:
-        builder.append_multiple_char('0', vdigits_end - buflen)
-
-    s = builder.build()
-
-    # Delete a trailing decimal pt unless using alternative formatting.
-    if not flags & rarithmetic.DTSF_ALT:
-        last = len(s) - 1
-        if last >= 0 and s[last] == '.':
-            s = s[:last]
-
-    # Now that we've done zero padding, add an exponent if needed.
-    if use_exp:
-        if exp >= 0:
-            exp_str = str(exp)
-            if len(exp_str) < 2:
-                s += 'e+0' + exp_str
-            else:
-                s += 'e+' + exp_str
-        else:
-            exp_str = str(-exp)
-            if len(exp_str) < 2:
-                s += 'e-0' + exp_str
-            else:
-                s += 'e-' + exp_str
-
-    return s
-
-def dtoa(value, code='r', mode=0, precision=0, flags=0):
-    with lltype.scoped_alloc(rffi.INTP.TO, 1) as decpt_ptr:
-        with lltype.scoped_alloc(rffi.INTP.TO, 1) as sign_ptr:
-            with lltype.scoped_alloc(rffi.CCHARPP.TO, 1) as end_ptr:
-                digits = dg_dtoa(value, mode, precision,
-                                     decpt_ptr, sign_ptr, end_ptr)
-                try:
-                    buflen = (rffi.cast(rffi.LONG, end_ptr[0]) -
-                              rffi.cast(rffi.LONG, digits))
-                    sign = rffi.cast(lltype.Signed, sign_ptr[0])
-
-                    # Handle nan and inf
-                    if buflen and not digits[0].isdigit():
-                        return format_nonfinite(digits, sign, flags)
-
-                    decpt = rffi.cast(lltype.Signed, decpt_ptr[0])
-
-                    return format_number(digits, buflen, sign, decpt,
-                                         code, precision, flags)
-
-                finally:
-                    dg_freedtoa(digits)
-
-def llimpl_strtod(value, code, precision, flags):
-    if code in 'EFG':
-        code = code.lower()
-
-    if code == 'e':
-        mode = 2
-        precision += 1
-    elif code == 'f':
-        mode = 3
-    elif code == 'g':
-        mode = 2
-        # precision 0 makes no sense for 'g' format; interpret as 1
-        if precision == 0:
-            precision = 1
-    elif code == 'r':
-        # repr format
-        mode = 0
-        assert precision == 0
-    else:
-        raise ValueError('Invalid mode')
-
-    return dtoa(value, code, mode=mode, precision=precision, flags=flags)

diff --git a/pypy/rpython/module/test/test_ll_dtoa.py b/pypy/rlib/test/test_rdtoa.py
copy from pypy/rpython/module/test/test_ll_dtoa.py
copy to pypy/rlib/test/test_rdtoa.py
--- a/pypy/rpython/module/test/test_ll_dtoa.py
+++ b/pypy/rlib/test/test_rdtoa.py
@@ -1,4 +1,5 @@
-from pypy.rpython.module.ll_dtoa import strtod, dtoa, rarithmetic
+from pypy.rlib.rdtoa import strtod, dtoa
+from pypy.rlib import rarithmetic
 
 def test_strtod():
     assert strtod("12345") == 12345.0

diff --git a/pypy/rlib/rarithmetic.py b/pypy/rlib/rarithmetic.py
--- a/pypy/rlib/rarithmetic.py
+++ b/pypy/rlib/rarithmetic.py
@@ -37,6 +37,8 @@
 from pypy.rpython import extregistry
 from pypy.rlib import objectmodel
 
+USE_SHORT_FLOAT_REPR = True # XXX make it a translation option?
+
 # set up of machine internals
 _bits = 0
 _itest = 1
@@ -615,8 +617,13 @@
         s = s[:-2]
 
     return s
+
 def formatd(x, code, precision, flags=0):
-    return _formatd(x, code, precision, flags)
+    if USE_SHORT_FLOAT_REPR:
+        from pypy.rlib.rdtoa import dtoa_formatd
+        return dtoa_formatd(x, code, precision, flags)
+    else:
+        return _formatd(x, code, precision, flags)
 
 formatd_max_length = 120
 

diff --git a/pypy/rpython/module/test/test_ll_dtoa.py b/pypy/rpython/module/test/test_ll_dtoa.py
deleted file mode 100644
--- a/pypy/rpython/module/test/test_ll_dtoa.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from pypy.rpython.module.ll_dtoa import strtod, dtoa, rarithmetic
-
-def test_strtod():
-    assert strtod("12345") == 12345.0
-    assert strtod("1.1") == 1.1
-    assert strtod("3.47") == 3.47
-    raises(ValueError, strtod, "123A")
-
-def test_dtoa():
-    assert dtoa(3.47) == "3.47"
-    assert dtoa(1.1) == "1.1"
-    assert dtoa(-1.1) == "-1.1"
-    assert dtoa(1.1, flags=rarithmetic.DTSF_SIGN) == "+1.1"
-    assert dtoa(12.3577) == "12.3577"
-    assert dtoa(10.0) == "10"
-    assert dtoa(1.0e100) == "1e+100"
-
-    assert dtoa(rarithmetic.INFINITY) == 'inf'
-    assert dtoa(-rarithmetic.INFINITY) == '-inf'
-    assert dtoa(rarithmetic.NAN) == 'nan'
-
-def test_dtoa_precision():
-    assert dtoa(1.1, code='f', precision=2) == "1.10"

diff --git a/pypy/rpython/module/ll_dtoa.py b/pypy/rlib/rdtoa.py
copy from pypy/rpython/module/ll_dtoa.py
copy to pypy/rlib/rdtoa.py
--- a/pypy/rpython/module/ll_dtoa.py
+++ b/pypy/rlib/rdtoa.py
@@ -221,7 +221,7 @@
                 finally:
                     dg_freedtoa(digits)
 
-def llimpl_strtod(value, code, precision, flags):
+def dtoa_formatd(value, code, precision, flags):
     if code in 'EFG':
         code = code.lower()
 


More information about the Pypy-commit mailing list