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