Author: mattip <[email protected]>
Branch: numpypy-longdouble
Changeset: r59544:5dac48fe33b5
Date: 2012-12-14 15:01 +0200
http://bitbucket.org/pypy/pypy/changeset/5dac48fe33b5/

Log:    progress packing, unpacking 80 bit extended format doubles, failing
        tests in test_ieee for inf, nan

diff --git a/pypy/module/micronumpy/test/test_numarray.py 
b/pypy/module/micronumpy/test/test_numarray.py
--- a/pypy/module/micronumpy/test/test_numarray.py
+++ b/pypy/module/micronumpy/test/test_numarray.py
@@ -2139,7 +2139,7 @@
             m = fromstring('\x00\x00\x00\x00\x00\x00\x00\xa0\x01@\x00\x00', 
dtype=float96)
         elif dt.itemsize==16:
             from _numpypy import float128
-            m = 
fromstring('\x00\x00\x00\x00\x00\x00\x00\xa0\x01@\x9c\xd3#\x7f\x00\x00', 
dtype=float128)
+            m = 
fromstring('\x00\x00\x00\x00\x00\x00\x00\xa0\x01@\x00\x00\x00\x00\x00\x00', 
dtype=float128)
         elif dt.itemsize == 8:
             skip('longfloat is float64')
         else:
@@ -2147,7 +2147,7 @@
         assert m[0] == longfloat(5.)
 
     def test_fromstring_invalid(self):
-        from _numpypy import fromstring, uint16, uint8, int32
+        from _numpypy import fromstring, uint16, uint8
         #default dtype is 64-bit float, so 3 bytes should fail
         raises(ValueError, fromstring, "\x01\x02\x03")
         #3 bytes is not modulo 2 bytes (int16)
diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py
--- a/pypy/module/micronumpy/types.py
+++ b/pypy/module/micronumpy/types.py
@@ -14,7 +14,8 @@
 from pypy.rpython.lltypesystem import lltype, rffi
 from pypy.rlib.rstruct.runpack import runpack
 from pypy.rlib.rstruct.nativefmttable import native_is_bigendian
-from pypy.rlib.rstruct.ieee import float_pack, float_unpack, unpack_float
+from pypy.rlib.rstruct.ieee import (float_pack, float_unpack, 
+                                    unpack_float, unpack_float128)
 from pypy.tool.sourcetools import func_with_new_name
 from pypy.rlib import jit
 from pypy.rlib.rstring import StringBuilder
@@ -1023,7 +1024,7 @@
 
         def runpack_str(self, s):
             assert len(s) == 16
-            fval = unpack_float(s, native_is_bigendian)
+            fval = unpack_float128(s, native_is_bigendian)
             return self.box(fval)
 
     class NonNativeFloat128(Float128):
diff --git a/pypy/rlib/rstruct/ieee.py b/pypy/rlib/rstruct/ieee.py
--- a/pypy/rlib/rstruct/ieee.py
+++ b/pypy/rlib/rstruct/ieee.py
@@ -25,18 +25,44 @@
         int_part += 1
     return int_part
 
+def float_unpack80(Q, size):
+    if size == 16 or size == 12:
+        #Implement a x86-hardware extended 80 bit format
+        MIN_EXP = -16381
+        MAX_EXP = 16384 
+        MANT_DIG = 64   
+        BITS = 80
+        one = r_ulonglonglong(1)
+    else:
+        raise ValueError("invalid size value")
+    if not objectmodel.we_are_translated():
+        # This tests generates wrong code when translated:
+        # with gcc, shifting a 64bit int by 64 bits does
+        # not change the value.
+        if Q >> BITS:
+            raise ValueError("input '%r' out of range '%r'" % (Q, Q>>BITS))
+
+    # extract pieces with explicit one in MANT_DIG
+    sign = rarithmetic.intmask(Q >> BITS - 1)
+    exp = rarithmetic.intmask((Q & ((one << BITS - 1) - (one << MANT_DIG - 
1))) >> MANT_DIG)
+    mant = Q & ((one << MANT_DIG) - 1) #value WITH explicit one
+
+    if exp == MAX_EXP - MIN_EXP + 2:
+        # nan or infinity
+        result = rfloat.NAN if mant else rfloat.INFINITY
+    elif exp == 0:
+        # subnormal or zero
+        result = math.ldexp(mant, MIN_EXP - MANT_DIG)
+    else:
+        # normal
+        result = math.ldexp(mant, exp + MIN_EXP - MANT_DIG - 1)
+    return -result if sign else result
+
 
 def float_unpack(Q, size):
     """Convert a 16-bit, 32-bit 64-bit integer created
     by float_pack into a Python float."""
-    if size == 16 or size == 12:
-        #Implement a x86-hardware extended 80 bit format
-        MIN_EXP = -16381  # = sys.float_info.min_exp
-        MAX_EXP = 16384   # = sys.float_info.max_exp
-        MANT_DIG = 64    # = sys.float_info.mant_dig
-        BITS = 80
-        one = r_ulonglonglong(1)
-    elif size == 8:
+    if size == 8:
         MIN_EXP = -1021  # = sys.float_info.min_exp
         MAX_EXP = 1024   # = sys.float_info.max_exp
         MANT_DIG = 53    # = sys.float_info.mant_dig
@@ -62,9 +88,9 @@
         # with gcc, shifting a 64bit int by 64 bits does
         # not change the value.
         if Q >> BITS:
-            raise ValueError("input out of range")
+            raise ValueError("input '%r' out of range '%r'" % (Q, Q>>BITS))
 
-    # extract pieces
+    # extract pieces with assumed 1.mant values
     sign = rarithmetic.intmask(Q >> BITS - 1)
     exp = rarithmetic.intmask((Q & ((one << BITS - 1) - (one << MANT_DIG - 
1))) >> MANT_DIG - 1)
     mant = Q & ((one << MANT_DIG - 1) - 1)
@@ -76,7 +102,7 @@
         # subnormal or zero
         result = math.ldexp(mant, MIN_EXP - MANT_DIG)
     else:
-        # normal
+        # normal: add implicit one value
         mant += one << MANT_DIG - 1
         result = math.ldexp(mant, exp + MIN_EXP - MANT_DIG - 1)
     return -result if sign else result
@@ -110,9 +136,10 @@
         BITS = 16
     elif size == 16 or size == 12:
         #Implement a x86-hardware extended 80 bit format
-        MIN_EXP = -16381  # = sys.float_info.min_exp
-        MAX_EXP = 16384   # = sys.float_info.max_exp
-        MANT_DIG = 64    # = sys.float_info.mant_dig
+        # with explicit 1 in bit 64
+        MIN_EXP = -16381
+        MAX_EXP = 16384
+        MANT_DIG = 64 
         BITS = 80
     else:
         raise ValueError("invalid size value")
@@ -160,7 +187,9 @@
         assert 0 <= mant < 1 << MANT_DIG - 1
         assert 0 <= exp <= MAX_EXP - MIN_EXP + 2
         assert 0 <= sign <= 1
-
+    if size==12 or size == 16:
+        mant |= r_type(1) <<(MANT_DIG-1) #1 is explicit for 80bit extended 
format
+        exp = exp << 1
     exp = r_type(exp)
     sign = r_type(sign)
     return ((sign << BITS - 1) | (exp << MANT_DIG - 1)) | mant
@@ -176,10 +205,16 @@
         l.reverse()
     result.append("".join(l))
 
-
 def unpack_float(s, be):
     unsigned = r_ulonglong(0)
     for i in range(len(s)):
         c = ord(s[len(s) - 1 - i if be else i])
         unsigned |= r_ulonglong(c) << (i * 8)
     return float_unpack(unsigned, len(s))
+
+def unpack_float128(s, be):
+    unsigned = r_ulonglonglong(0)
+    for i in range(len(s)):
+        c = ord(s[len(s) - 1 - i if be else i])
+        unsigned |= r_ulonglonglong(c) << (i * 8)
+    return float_unpack80(unsigned, len(s))
diff --git a/pypy/rlib/rstruct/test/test_ieee.py 
b/pypy/rlib/rstruct/test/test_ieee.py
--- a/pypy/rlib/rstruct/test/test_ieee.py
+++ b/pypy/rlib/rstruct/test/test_ieee.py
@@ -3,7 +3,7 @@
 import struct
 
 from pypy.rlib.rfloat import isnan
-from pypy.rlib.rstruct.ieee import float_pack, float_unpack, float_pack128
+from pypy.rlib.rstruct.ieee import float_pack, float_unpack, float_pack128, 
float_unpack80
 
 
 class TestFloatPacking:
@@ -19,11 +19,11 @@
         assert repr(x) == repr(y)
 
         Q = float_pack128(x, 16)
-        y = float_unpack(Q, 16)
-        assert repr(x) == repr(y)
+        y = float_unpack80(Q, 16)
+        assert repr(x) == repr(y),'%r != %r, Q=%r'%(x, y, Q)
         Q = float_pack128(x, 12)
-        y = float_unpack(Q, 12)
-        assert repr(x) == repr(y)
+        y = float_unpack80(Q, 12)
+        assert repr(x) == repr(y),'%r != %r, Q=%r'%(x, y, Q)
 
         # check that packing agrees with the struct module
         struct_pack8 = struct.unpack('<Q', struct.pack('<d', x))[0]
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to