[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