[pypy-svn] r46929 - in pypy/dist/pypy: annotation rlib rlib/test rpython/lltypesystem rpython/lltypesystem/test rpython/test

arigo at codespeak.net arigo at codespeak.net
Thu Sep 27 11:08:20 CEST 2007


Author: arigo
Date: Thu Sep 27 11:08:18 2007
New Revision: 46929

Modified:
   pypy/dist/pypy/annotation/model.py
   pypy/dist/pypy/rlib/rarithmetic.py
   pypy/dist/pypy/rlib/test/test_rarithmetic.py
   pypy/dist/pypy/rpython/lltypesystem/lltype.py
   pypy/dist/pypy/rpython/lltypesystem/rffi.py
   pypy/dist/pypy/rpython/lltypesystem/test/test_lltype.py
   pypy/dist/pypy/rpython/test/test_rfloat.py
Log:
Minimal support for single-precision floats in lltype and rarithmetic.


Modified: pypy/dist/pypy/annotation/model.py
==============================================================================
--- pypy/dist/pypy/annotation/model.py	(original)
+++ pypy/dist/pypy/annotation/model.py	Thu Sep 27 11:08:18 2007
@@ -33,6 +33,7 @@
 from pypy.annotation.pairtype import pair, extendabletype
 from pypy.tool.tls import tlsobject
 from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong, base_int
+from pypy.rlib.rarithmetic import r_singlefloat
 import inspect, weakref
 from sys import maxint
 from pypy.annotation.description import FunctionDesc
@@ -154,6 +155,15 @@
     def can_be_none(self):
         return False
 
+class SomeSingleFloat(SomeObject):
+    "Stands for an r_singlefloat."
+    # No operation supported, not even union with a regular float
+    knowntype = r_singlefloat
+    immutable = True
+
+    def can_be_none(self):
+        return False
+
 class SomeInteger(SomeFloat):
     "Stands for an object which is known to be an integer."
     knowntype = int
@@ -576,6 +586,7 @@
     (s_Bool, lltype.Bool),
     (SomeInteger(knowntype=r_ulonglong), NUMBER),    
     (SomeFloat(), lltype.Float),
+    (SomeSingleFloat(), lltype.SingleFloat),
     (SomeChar(), lltype.Char),
     (SomeUnicodeCodePoint(), lltype.UniChar),
     (SomeAddress(), llmemory.Address),

Modified: pypy/dist/pypy/rlib/rarithmetic.py
==============================================================================
--- pypy/dist/pypy/rlib/rarithmetic.py	(original)
+++ pypy/dist/pypy/rlib/rarithmetic.py	Thu Sep 27 11:08:18 2007
@@ -438,3 +438,77 @@
         if x == 0:
             x = -1
     return intmask(x)
+
+# the 'float' C type
+
+class r_singlefloat(object):
+    """A value of the C type 'float'.
+
+    This is a single-precision floating-point number.
+    Regular 'float' values in Python and RPython are double-precision.
+    Note that we consider this as a black box for now - the only thing
+    you can do with it is cast it back to a regular float."""
+
+    def __init__(self, floatval):
+        import struct
+        # simulates the loss of precision
+        self._bytes = struct.pack("f", floatval)
+
+    def __float__(self):
+        import struct
+        return struct.unpack("f", self._bytes)[0]
+
+    def __nonzero__(self):
+        raise TypeError("not supported on r_singlefloat instances")
+
+    def __cmp__(self, other):
+        raise TypeError("not supported on r_singlefloat instances")
+
+
+class For_r_singlefloat_values_Entry(extregistry.ExtRegistryEntry):
+    _type_ = r_singlefloat
+
+    def compute_annotation(self):
+        return _somesinglefloat()
+
+class For_r_singlefloat_type_Entry(extregistry.ExtRegistryEntry):
+    _about_ = r_singlefloat
+
+    def compute_result_annotation(self, *args_s, **kwds_s):
+        return _somesinglefloat()
+
+    def specialize_call(self, hop):
+        from pypy.rpython.lltypesystem import lltype
+        v, = hop.inputargs(lltype.Float)
+        hop.exception_cannot_occur()
+        # we use cast_primitive to go between Float and SingleFloat.
+        return hop.genop('cast_primitive', [v],
+                         resulttype = lltype.SingleFloat)
+
+def _somesinglefloat():
+    """Returns SomeSingleFloat(), but also lazily register the rtyping support
+    for SomeSingleFloat.
+    """
+    from pypy.annotation import model as annmodel
+
+    if 'rtyper_makerepr' not in annmodel.SomeSingleFloat.__dict__:
+        from pypy.rpython.lltypesystem import lltype
+        from pypy.rpython.rmodel import Repr
+
+        class SingleFloatRepr(Repr):
+            lowleveltype = lltype.SingleFloat
+
+            def rtype_float(self, hop):
+                v, = hop.inputargs(lltype.SingleFloat)
+                hop.exception_cannot_occur()
+                # we use cast_primitive to go between Float and SingleFloat.
+                return hop.genop('cast_primitive', [v],
+                                 resulttype = lltype.Float)
+
+        class __extend__(annmodel.SomeSingleFloat):
+            def rtyper_makerepr(self, rtyper):
+                return SingleFloatRepr()
+            def rtyper_makekey(self):
+                return self.__class__,
+
+    return annmodel.SomeSingleFloat()

Modified: pypy/dist/pypy/rlib/test/test_rarithmetic.py
==============================================================================
--- pypy/dist/pypy/rlib/test/test_rarithmetic.py	(original)
+++ pypy/dist/pypy/rlib/test/test_rarithmetic.py	Thu Sep 27 11:08:18 2007
@@ -295,6 +295,13 @@
 
     py.test.raises(ValueError, break_up_float, 'e')
 
+def test_r_singlefloat():
+    x = r_singlefloat(2.5)       # exact number
+    assert float(x) == 2.5
+    x = r_singlefloat(2.1)       # approximate number, bits are lost
+    assert float(x) != 2.1
+    assert abs(float(x) - 2.1) < 1E-6
+
 class BaseTestRarithmetic(BaseRtypingTest):
     def test_formatd(self):
         from pypy.rlib.rarithmetic import formatd

Modified: pypy/dist/pypy/rpython/lltypesystem/lltype.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/lltype.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/lltype.py	Thu Sep 27 11:08:18 2007
@@ -1,5 +1,5 @@
 import py
-from pypy.rlib.rarithmetic import r_int, r_uint, intmask
+from pypy.rlib.rarithmetic import r_int, r_uint, intmask, r_singlefloat
 from pypy.rlib.rarithmetic import r_ulonglong, r_longlong, base_int
 from pypy.rlib.rarithmetic import normalizedinttype
 from pypy.rlib.objectmodel import Symbolic
@@ -584,7 +584,10 @@
 SignedLongLong = build_number("SignedLongLong", r_longlong)
 UnsignedLongLong = build_number("UnsignedLongLong", r_ulonglong)
 
-Float    = Primitive("Float", 0.0)
+Float       = Primitive("Float",       0.0)                  # C type 'double'
+SingleFloat = Primitive("SingleFloat", r_singlefloat(0.0))   # C type 'float'
+r_singlefloat._TYPE = SingleFloat
+
 Char     = Primitive("Char", '\x00')
 Bool     = Primitive("Bool", False)
 Void     = Primitive("Void", None)
@@ -680,12 +683,16 @@
     if ORIG == Char or ORIG == UniChar:
         value = ord(value)
     elif ORIG == Float:
+        if TGT == SingleFloat:
+            return r_singlefloat(value)
         value = long(value)
     cast = _to_primitive.get(TGT)
     if cast is not None:
         return cast(value)
     if isinstance(TGT, Number):
         return TGT._cast(value)
+    if ORIG == SingleFloat and TGT == Float:
+        return float(value)
     raise TypeError, "unsupported cast"
 
 def _cast_whatever(TGT, value):

Modified: pypy/dist/pypy/rpython/lltypesystem/rffi.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/rffi.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/rffi.py	Thu Sep 27 11:08:18 2007
@@ -254,9 +254,13 @@
 # (use SIGNEDCHAR or UCHAR for the small integer types)
 CHAR = lltype.Char
 
-# double  - XXX there is no support for the C type 'float' in the C backend yet
+# double
 DOUBLE = lltype.Float
 
+# float - corresponds to pypy.rlib.rarithmetic.r_float, and supports no
+#         operation except rffi.cast() between FLOAT and DOUBLE
+FLOAT = lltype.SingleFloat
+
 # void *   - for now, represented as char *
 VOIDP = lltype.Ptr(lltype.Array(lltype.Char, hints={'nolength': True}))
 

Modified: pypy/dist/pypy/rpython/lltypesystem/test/test_lltype.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/test/test_lltype.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/test/test_lltype.py	Thu Sep 27 11:08:18 2007
@@ -549,6 +549,7 @@
 def test_cast_primitive():
     cases = [
         (Float, 1, 1.0),
+        (Float, r_singlefloat(2.1), float(r_singlefloat(2.1))),
         (Signed, 1.0, 1),
         (Unsigned, 1.0, 1),
         (Signed, r_uint(-1), -1),
@@ -562,6 +563,9 @@
          res = cast_primitive(TGT, orig_val)
          assert typeOf(res) == TGT
          assert res == expect
+    res = cast_primitive(SingleFloat, 2.1)
+    assert isinstance(res, r_singlefloat)
+    assert float(res) == float(r_singlefloat(2.1))
 
 def test_cast_identical_array_ptr_types():
     A = GcArray(Signed)

Modified: pypy/dist/pypy/rpython/test/test_rfloat.py
==============================================================================
--- pypy/dist/pypy/rpython/test/test_rfloat.py	(original)
+++ pypy/dist/pypy/rpython/test/test_rfloat.py	Thu Sep 27 11:08:18 2007
@@ -2,7 +2,7 @@
 from pypy.translator.translator import TranslationContext
 from pypy.rpython.test import snippet
 from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin
-from pypy.rlib.rarithmetic import r_uint, r_longlong
+from pypy.rlib.rarithmetic import r_uint, r_longlong, r_singlefloat
 
 class TestSnippet(object):
 
@@ -94,6 +94,15 @@
         res = self.interpret(fn, [-9])
         assert self.float_eq(res, 0.5 * ((sys.maxint+1)*2 - 9))
 
+    def test_r_singlefloat(self):
+        def fn(x):
+            y = r_singlefloat(x)
+            return float(y)
+
+        res = self.interpret(fn, [2.1])
+        assert res != 2.1     # precision lost
+        assert abs(res - 2.1) < 1E-6
+
     def test_float_constant_conversions(self):
         DIV = r_longlong(10 ** 10)
         def fn():



More information about the Pypy-commit mailing list