[pypy-commit] pypy numpypy-longdouble: implement uint64-tuple representation of long double, break inf, nan handling
mattip
noreply at buildbot.pypy.org
Tue Dec 25 22:05:28 CET 2012
Author: mattip <matti.picus at gmail.com>
Branch: numpypy-longdouble
Changeset: r59550:b504a5a69cf9
Date: 2012-12-25 03:14 +0200
http://bitbucket.org/pypy/pypy/changeset/b504a5a69cf9/
Log: implement uint64-tuple representation of long double, break inf,nan
handling
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
@@ -26,6 +26,8 @@
return int_part
def float_unpack80(QQ, size):
+ '''Unpack a (mant, exp) tuple of r_ulonglong into a long double float
+ '''
if size == 16 or size == 12:
#Implement a x86-hardware extended 80 bit format as two 64 bit uints
# QQ[0] is the sign and exp, QQ[1] is the mant
@@ -42,13 +44,13 @@
# This tests generates wrong code when translated:
# with gcc, shifting a 64bit int by 64 bits does
# not change the value.
- if QQ[0] >> TOPBITS:
- raise ValueError("input '%r' out of range '%r'" % (QQ, QQ[0]>>TOPBITS))
+ if QQ[1] >> TOPBITS:
+ raise ValueError("input '%r' out of range '%r'" % (QQ, QQ[1]>>TOPBITS))
# extract pieces with explicit one in MANT_DIG
- sign = rarithmetic.intmask(QQ[0] >> TOPBITS - 1)
- exp = rarithmetic.intmask((QQ[0] & ((one << TOPBITS - 1) - 1)))
- mant = QQ[1]
+ sign = rarithmetic.intmask(QQ[1] >> TOPBITS - 1)
+ exp = rarithmetic.intmask((QQ[1] & ((one << TOPBITS - 1) - 1)))
+ mant = QQ[0]
if exp == MAX_EXP - MIN_EXP + 2:
# nan or infinity
@@ -111,9 +113,6 @@
def float_pack(x, size):
"""Convert a Python float x into a 64-bit unsigned integer
with the same byte representation."""
- return float_pack_helper(x, size, r_ulonglong)
-
-def float_pack_helper(x, size, r_ulonglong):
if size == 8:
MIN_EXP = -1021 # = sys.float_info.min_exp
MAX_EXP = 1024 # = sys.float_info.max_exp
@@ -189,6 +188,65 @@
sign = r_ulonglong(sign)
return ((sign << BITS - 1) | (exp << MANT_DIG - 1)) | mant
+def float_pack80(x, size):
+ """Convert a Python float x into two 64-bit unsigned integers
+ with the same byte representation."""
+ if size == 16 or size == 12:
+ #Implement a x86-hardware extended 80 bit format
+ # with explicit 1 in bit 64
+ MIN_EXP = -16381
+ MAX_EXP = 16384
+ MANT_DIG = 64
+ BITS = 80
+ else:
+ raise ValueError("invalid size value")
+
+ sign = rfloat.copysign(1.0, x) < 0.0
+ if not rfloat.isfinite(x):
+ if rfloat.isinf(x):
+ mant = r_ulonglong(0)
+ exp = MAX_EXP - MIN_EXP + 2
+ else: # rfloat.isnan(x):
+ mant = r_ulonglong(1) << (MANT_DIG-2) # other values possible
+ exp = MAX_EXP - MIN_EXP + 2
+ elif x == 0.0:
+ mant = r_ulonglong(0)
+ exp = 0
+ else:
+ m, e = math.frexp(abs(x)) # abs(x) == m * 2**e
+ exp = e - (MIN_EXP - 1)
+ if exp > 0:
+ # Normal case. Avoid uint64 overflow by using MANT_DIG-1
+ mant = round_to_nearest(m * (r_ulonglong(1) << MANT_DIG - 1))
+ else:
+ # Subnormal case.
+ if exp + MANT_DIG - 1 >= 0:
+ mant = round_to_nearest(m * (r_ulonglong(1) << exp + MANT_DIG - 1))
+ else:
+ mant = r_ulonglong(0)
+ exp = 0
+
+ # Special case: rounding produced a MANT_DIG-bit mantissa.
+ if mant == r_ulonglong(1) << MANT_DIG - 1:
+ mant = r_ulonglong(0)
+ exp += 1
+
+ # Raise on overflow (in some circumstances, may want to return
+ # infinity instead).
+ if exp >= MAX_EXP - MIN_EXP + 2:
+ raise OverflowError("float too large to pack in this format")
+
+ # check constraints
+ if not objectmodel.we_are_translated():
+ 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 = mant << 1
+ exp = r_ulonglong(exp)
+ sign = r_ulonglong(sign)
+ return (mant, (sign << BITS - MANT_DIG - 1) | exp)
+
@jit.unroll_safe
def pack_float(result, x, size, be):
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, float_unpack80
+from pypy.rlib.rstruct.ieee import float_pack, float_unpack, float_pack80, float_unpack80
class TestFloatPacking:
@@ -18,10 +18,10 @@
y = float_unpack(Q, 8)
assert repr(x) == repr(y)
- Q = float_pack128(x, 16)
+ Q = float_pack80(x, 16)
y = float_unpack80(Q, 16)
assert repr(x) == repr(y),'%r != %r, Q=%r'%(x, y, Q)
- Q = float_pack128(x, 12)
+ Q = float_pack80(x, 12)
y = float_unpack80(Q, 12)
assert repr(x) == repr(y),'%r != %r, Q=%r'%(x, y, Q)
@@ -65,10 +65,10 @@
self.check_float(-0.0)
def test_nans(self):
- Q = float_pack128(float('nan'), 16)
+ Q = float_pack80(float('nan'), 16)
y = float_unpack80(Q, 16)
assert repr(y) == 'nan'
- Q = float_pack128(float('nan'), 12)
+ Q = float_pack80(float('nan'), 12)
y = float_unpack80(Q, 12)
assert repr(y) == 'nan'
Q = float_pack(float('nan'), 8)
More information about the pypy-commit
mailing list