[pypy-commit] pypy numpypy.float16: remove halffloat, use rstruct/ieee instead
mattip
noreply at buildbot.pypy.org
Mon Nov 5 20:08:31 CET 2012
Author: mattip <matti.picus at gmail.com>
Branch: numpypy.float16
Changeset: r58742:732cf0bce873
Date: 2012-11-05 21:06 +0200
http://bitbucket.org/pypy/pypy/changeset/732cf0bce873/
Log: remove halffloat, use rstruct/ieee instead
diff --git a/pypy/module/micronumpy/halffloat.py b/pypy/module/micronumpy/halffloat.py
deleted file mode 100644
--- a/pypy/module/micronumpy/halffloat.py
+++ /dev/null
@@ -1,179 +0,0 @@
-# Based on numpy's halffloat.c, this is an implementation of routines
-# for 16 bit float values.
-from pypy.rpython.lltypesystem import rffi
-
-
-def halfbits_to_floatbits(x):
- x = rffi.cast(rffi.UINT, x)
- h_exp = x & 0x7c00
- f_sgn = (x & 0x8000) << 16
- if h_exp == 0: #0 or subnormal
- h_sig = x & 0x03ff
- if h_sig == 0:
- return f_sgn
- #Subnormal
- h_sig <<= 1;
- while (h_sig & 0x0400) == 0:
- h_sig <<= 1
- h_exp += 1
- f_exp = 127 - 15 - h_exp << 23
- f_sig = h_sig & 0x03ff << 13
- return f_sgn + f_exp + f_sig
- elif h_exp == 0x7c00: # inf or nan
- return f_sgn + 0x7f800000 + ((x & 0x03ff) << 13)
- # Just need to adjust the exponent and shift
- return f_sgn +((rffi.cast(rffi.UINT,(x & 0x7fff)) + 0x1c000) << 13)
-
-
-def floatbits_to_halfbits(f):
- h_sgn = (f >>16) & 0x8000
- f_exp = f & 0x7f800000
- if f_exp >= 0x47800000:
- # Exponent overflow, convert to signed inf/nan
- if f_exp == 0x7f800000:
- # inf or nan
- f_sig = f & 0x007fffff
- if f_sig != 0:
- #nan - propagate the flag in the significand
- ret = 0x7c00 + (f_sig >> 13)
- # ... but make sure it stays a nan
- if ret == 0x7c00:
- ret += 1
- return h_sgn + ret
- else:
- # signed inf
- return h_sgn + 0x7c00
- else:
- # overflow to signed inf
- # npy_set_floatstatus_overflow()
- return h_sgn + 0x7c00
- if f_exp <= 0x38000000:
- # Exponent underflow converts to a subnormal half or signed zero
- if f_exp < 0x33000000:
- # Signed zeros, subnormal floats, and floats with small
- # exponents all conver to signed zero halfs
- if f & 0x7fffffff != 0:
- pass
- # npy_set_floatstatus_underflow()
- return h_sgn
- # Make the subnormal significand
- f_exp >>= 23
- f_sig = 0x00800000 + (f & 0x007fffff)
- if (f_sig & ((1 << (126 - f_exp)) -1)) != 0:
- # not exactly represented, therefore underflowed
- pass
- # npy_set_floatstatus_underflow()
- f_sig >>= (113 - f_exp)
- # Handle rounding by adding 1 to the bit beyond half precision
- if (f_sig & 0x00003fff) != 0x00001000:
- # The last remaining bit is 1, and the rmaining bit pattern
- # is not 1000...0, so round up
- f_sig += 0x00001000
- h_sig = f_sig >> 13
- # If the rounding caused a bit to spill into h_exp, it will
- # increment h_exp from zero to one and h_sig will remain zero
- # which is the correct result.
- return h_sgn + h_sig
- # No overflow or underflow
- h_exp = (f_exp - 0x38000000)>> 13
- f_sig = f & 0x007fffff
- if (f_sig & 0x00003fff) != 0x00001000:
- # The last remaining bit is 1, and the rmaining bit pattern
- # is not 1000...0, so round up
- f_sig += 0x00001000
- h_sig = f_sig >> 13
- # If the rounding cuased a bit to spill into h_exp, it will
- # increment h_exp from zero to one and h_sig will remain zero
- # which is the correct result. However, h_exp may increment to
- # 15, at greatest, in which case the result overflows
- h_sig += h_exp
- if h_sig == 0x7c00:
- pass
- #npy_set_floatstatus_overflow()
- return h_sgn + h_sig
-
-def halfbits_to_doublebits(h):
- h_exp = h & 0x7c00
- d_sgn = h >>15 << 63
- if h_exp == 0: #0 or subnormal
- h_sig = h & 0x03ff
- if h_sig == 0:
- return d_sgn
- #Subnormal
- h_sig <<= 1;
- while (h_sig & 0x0400) == 0:
- h_sig <<= 1
- h_exp += 1
- d_exp = ((1023 - 15 - h_exp)) << 52
- d_sig = ((h_sig & 0x03ff)) << 42
- return d_sgn + d_exp + d_sig;
- elif h_exp == 0x7c00: # inf or nan
- return d_sgn + 0x7ff0000000000000 + ((h & 0x03ff) << 42)
- return d_sgn + (((h & 0x7fff) + 0xfc000) << 42)
-
-def doublebits_to_halfbits(d):
- h_sgn = (d & 0x8000000000000000) >> 48
- d_exp = (d & 0x7ff0000000000000)
- if d_exp >= 0x40f0000000000000:
- # Exponent overflow, convert to signed inf/nan
- if d_exp == 0x7ff0000000000000:
- # inf or nan
- d_sig = d & 0x000fffffffffffff
- if d_sig != 0:
- #nan - propagate the flag in the significand
- ret = 0x7c00 + (d_sig >> 42)
- # ... but make sure it stays a nan
- if ret == 0x7c00:
- ret += 1
- return h_sgn + ret
- else:
- # signed inf
- return h_sgn + 0x7c00
- else:
- # overflow to signed inf
- # npy_set_floatstatus_overflow()
- return h_sgn + 0x7c00
- if d_exp <= 0x3f00000000000000:
- # Exponent underflow converts to a subnormal half or signed zero
- if d_exp < 0x3e60000000000000:
- # Signed zeros, subnormal floats, and floats with small
- # exponents all conver to signed zero halfs
- if d & 0x7fffffffffffffff != 0:
- pass
- # npy_set_floatstatus_underflow()
- return h_sgn
- # Make the subnormal significand
- d_exp >>= 52
- d_sig = 0x0010000000000000 + (d & 0x000fffffffffffff)
- if (d_sig & ((1 << (1051 - d_exp)) - 1)) != 0:
- # not exactly represented, therefore underflowed
- pass
- # npy_set_floatstatus_underflow()
- d_sig >>= (1009 - d_exp)
- # Handle rounding by adding 1 to the bit beyond half precision
- if (d_sig & 0x000007ffffffffff) != 0x0000020000000000:
- # The last remaining bit is 1, and the rmaining bit pattern
- # is not 1000...0, so round up
- d_sig += 0x0000020000000000
- h_sig = d_sig >> 42
- # If the rounding caused a bit to spill into h_exp, it will
- # increment h_exp from zero to one and h_sig will remain zero
- # which is the correct result.
- return h_sgn + h_sig
- # No overflow or underflow
- h_exp = (d_exp - 0x3f00000000000000) >> 42
- d_sig = d & 0x000fffffffffffff
- if (d_sig & 0x000007ffffffffff) != 0x0000020000000000:
- # The last remaining bit is 1, and the rmaining bit pattern
- # is not 1000...0, so round up
- d_sig += 0x0000020000000000
- h_sig = d_sig >> 42
- # If the rounding cuased a bit to spill into h_exp, it will
- # increment h_exp from zero to one and h_sig will remain zero
- # which is the correct result. However, h_exp may increment to
- # 15, at greatest, in which case the result overflows
- h_sig += h_exp
- if h_sig == 0x7c00:
- pass
- #npy_set_floatstatus_overflow()
- return h_sgn + h_sig
diff --git a/pypy/module/micronumpy/test/test_halffloat.py b/pypy/module/micronumpy/test/test_halffloat.py
deleted file mode 100644
--- a/pypy/module/micronumpy/test/test_halffloat.py
+++ /dev/null
@@ -1,79 +0,0 @@
-
-from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest
-
-class AppTestUfuncs(BaseNumpyAppTest):
- def setup_class(cls):
- BaseNumpyAppTest.setup_class.im_func(cls)
- from pypy.module.micronumpy import halffloat
- cls.w_halffloat = cls.space.wrap(halffloat)
-
- def test_bitconvert_exact_f(self):
- #from _numpypy import array, uint32 ## Do this when 'view' works
- # These test cases were created by
- # numpy.float32(v).view(uint32)
- # numpy.float16(v).view(uint16)
- cases = [[0., 0, 0], [10, 1092616192, 18688], [-10, 3240099840, 51456],
- [10e3, 1176256512, 28898], [float('inf'), 2139095040, 31744],
- [-float('inf'), 4286578688, 64512],
- [5., 1084227584, 17664],]
- for v, fbits, hbits in cases:
- # No 'view' in numpypy yet
- # fbits = array(v, dtype='float32').view(uint32)
- f = self.halffloat.floatbits_to_halfbits(fbits)
- assert [f, v] == [hbits, v]
- f = self.halffloat.halfbits_to_floatbits(hbits)
- assert [f, v] == [fbits, v]
-
- def test_bitconvert_inexact_f(self):
- # finexact is
- # numpy.float32(numpy.float16(v)).view(uint32)
- cases = [[10.001, 1092617241, 1092616192, 18688],
- [-10.001, 3240100889, 3240099840, 51456],
- [22001.0, 1185669632, 1185669120, 30047],]
- for v, fexact, finexact, hbits in cases:
- f = self.halffloat.floatbits_to_halfbits(fexact)
- assert [f, v] == [hbits, v]
- f = self.halffloat.halfbits_to_floatbits(hbits)
- assert [f, v] == [finexact, v]
-
- def test_bitconvert_overunderflow_f(self):
- cases = [[67000.0, 1199758336, 2139095040, 31744],
- [-67000.0, 3347241984, 4286578688, 64512],
- [1e-08, 841731191, 0, 0],
- [-1e-08, 2989214839, 2147483648, 32768],
- ]
- for v, fexact, finexact, hbits in cases:
- f = self.halffloat.floatbits_to_halfbits(fexact)
- assert [f, v] == [hbits, v]
- f = self.halffloat.halfbits_to_floatbits(hbits)
- assert [f, v] == [finexact, v]
-
- def test_bitconvert_exact_d(self):
- #from _numpypy import array, uint32 ## Do this when 'view' works
- # These test cases were created by
- # numpy.float64(v).view(uint64)
- # numpy.float16(v).view(uint16)
- cases =[[0, 0, 0], [10, 4621819117588971520, 18688],
- [-10, 13845191154443747328, 51456],
- [10000.0, 4666723172467343360, 28898],
- [float('inf'), 9218868437227405312, 31744],
- [-float('inf'), 18442240474082181120, 64512]]
- for v, dbits, hbits in cases:
- # No 'view' in numpypy yet
- # dbits = array(v, dtype='float64').view(uint64)
- h = self.halffloat.doublebits_to_halfbits(dbits)
- assert [h, v] == [hbits, v]
- d = self.halffloat.halfbits_to_doublebits(hbits)
- assert [d, v] == [dbits, v]
-
- def test_bitconvert_inexact_d(self):
- # finexact is
- # numpy.float64(numpy.float16(v)).view(uint64)
- cases = [[10.001, 4621819680538924941, 4621819117588971520, 18688],
- [-10.001, 13845191717393700749, 13845191154443747328, 51456],
- [22001, 4671776802786508800, 4671776527908601856, 30047]]
- for v, fexact, finexact, hbits in cases:
- f = self.halffloat.doublebits_to_halfbits(fexact)
- assert [f, v] == [hbits, v]
- f = self.halffloat.halfbits_to_doublebits(hbits)
- assert [f, v] == [finexact, v]
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
@@ -19,8 +19,6 @@
from pypy.rlib import jit
from pypy.rlib.rstring import StringBuilder
-from pypy.module.micronumpy import halffloat
-
degToRad = math.pi / 180.0
log2 = math.log(2)
log2e = 1. / log2
@@ -930,8 +928,7 @@
BoxType = interp_boxes.W_Float16Box
def pack_str(self, box):
- fbits = float_pack(self.unbox(box), 4)
- hbits = halffloat.floatbits_to_halfbits(fbits)
+ hbits = float_pack(self.unbox(box), 2)
return struct.pack('H', hbits)
def get_element_size(self):
@@ -940,8 +937,7 @@
def runpack_str(self, s):
hbits = rffi.cast(rffi.UINT, runpack('H', s))
assert hbits >=0
- fbits = halffloat.halfbits_to_floatbits(hbits)
- return self.box(float_unpack(fbits, 4))
+ return self.box(float_unpack(hbits, 2))
def for_computation(self, v):
return float(v)
@@ -950,15 +946,13 @@
return self.box(-1.0)
def _read(self, storage, i, offset):
- byte_rep = rffi.cast(rffi.UINT,
+ hbits = rffi.cast(rffi.UINT,
raw_storage_getitem(self._STORAGE_T, storage, i + offset))
- assert byte_rep >=0
- fbits = halffloat.halfbits_to_floatbits(byte_rep)
- return float_unpack(fbits, 4)
+ assert hbits >=0
+ return float_unpack(hbits, 2)
def _write(self, storage, i, offset, value):
- fbits = float_pack(value,4)
- hbits = halffloat.floatbits_to_halfbits(fbits)
+ hbits = float_pack(value,2)
raw_storage_setitem(storage, i + offset,
rffi.cast(self._STORAGE_T, hbits))
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
@@ -112,6 +112,7 @@
self.check_float(x)
def test_halffloat_exact(self):
+ #testcases generated from numpy.float16(x).view('uint16')
cases = [[0, 0], [10, 18688], [-10, 51456], [10e3, 28898],
[float('inf'), 31744], [-float('inf'), 64512]]
for c,h in cases:
@@ -120,6 +121,7 @@
assert c == float_unpack(h, 2)
def test_halffloat_inexact(self):
+ #testcases generated from numpy.float16(x).view('uint16')
cases = [[10.001, 18688, 10.], [-10.001, 51456, -10],
[0.027588, 10000, 0.027587890625],
[22001, 30047, 22000]]
More information about the pypy-commit
mailing list