Commits

mattip committed 96359ae Merge

merge numpypy.float16 (a branch to support float16 container type for numypy)
into default. This container converts to python float for all operations.

Comments (0)

Files changed (13)

pypy/doc/whatsnew-head.rst

 Complex dtype support for numpy
 .. branch: numpypy-problems
 Improve dtypes intp, uintp, void, string and record
+.. branch: numpypy.float16
+Add float16 numpy dtype
 .. branch: kill-someobject
 major cleanups including killing some object support
 .. branch: cpyext-PyThreadState_New
Add a comment to this file

pypy/interpreter/argument.py

File contents unchanged.

Add a comment to this file

pypy/interpreter/test/test_argument.py

File contents unchanged.

pypy/module/micronumpy/__init__.py

         'inexact': 'interp_boxes.W_InexactBox',
         'floating': 'interp_boxes.W_FloatingBox',
         'float_': 'interp_boxes.W_Float64Box',
+        'float16': 'interp_boxes.W_Float16Box',
         'float32': 'interp_boxes.W_Float32Box',
         'float64': 'interp_boxes.W_Float64Box',
         'intp': 'types.IntP.BoxType',

pypy/module/micronumpy/interp_boxes.py

 class W_FloatingBox(W_InexactBox):
     _attrs_ = ()
 
+class W_Float16Box(W_FloatingBox, PrimitiveBox):
+    descr__new__, _get_dtype = new_dtype_getter("float16")
+
 class W_Float32Box(W_FloatingBox, PrimitiveBox):
     descr__new__, _get_dtype = new_dtype_getter("float32")
 
     __module__ = "numpypy",
 )
 
+W_Float16Box.typedef = TypeDef("float16", W_FloatingBox.typedef,
+    __module__ = "numpypy",
+
+    __new__ = interp2app(W_Float16Box.descr__new__.im_func),
+)
+
 W_Float32Box.typedef = TypeDef("float32", W_FloatingBox.typedef,
     __module__ = "numpypy",
 

pypy/module/micronumpy/interp_dtype.py

             #alternate_constructors=[space.w_buffer],
             # XXX no buffer in space
         )
+        self.w_float16dtype = W_Dtype(
+            types.Float16(),
+            num=23,
+            kind=FLOATINGLTR,
+            name="float16",
+            char="e",
+            w_box_type=space.gettypefor(interp_boxes.W_Float16Box),
+        )
         ptr_size = rffi.sizeof(rffi.CCHARP)
         if ptr_size == 4:
             intp_box = interp_boxes.W_Int32Box
             self.w_int16dtype, self.w_uint16dtype, self.w_int32dtype,
             self.w_uint32dtype, self.w_longdtype, self.w_ulongdtype,
             self.w_int64dtype, self.w_uint64dtype,
-            self.w_float32dtype, self.w_float64dtype, self.w_complex64dtype,
+            self.w_float16dtype, self.w_float32dtype, self.w_float64dtype, self.w_complex64dtype,
             self.w_complex128dtype,
             self.w_stringdtype, self.w_unicodedtype,
             self.w_voiddtype, self.w_intpdtype, self.w_uintpdtype,
         ]
         self.float_dtypes_by_num_bytes = sorted(
             (dtype.itemtype.get_element_size(), dtype)
-            for dtype in [self.w_float32dtype, self.w_float64dtype]
+            for dtype in [self.w_float16dtype, self.w_float32dtype, self.w_float64dtype]
         )
         self.dtypes_by_name = {}
         # we reverse, so the stuff with lower numbers override stuff with

pypy/module/micronumpy/interp_ufuncs.py

         dtypenum = dt2.num + 1
         # UInt64 + signed = Float64
         if dt2.num == 10:
-            dtypenum += 1
+            dtypenum += 2
     newdtype = interp_dtype.get_dtype_cache(space).builtin_dtypes[dtypenum]
 
     if (newdtype.itemtype.get_element_size() > dt2.itemtype.get_element_size() or
         if LONG_BIT == 32:
             dtypenum += 2
         else:
-            dtypenum += 3
+            dtypenum += 4
         return interp_dtype.get_dtype_cache(space).builtin_dtypes[dtypenum]
 
 

pypy/module/micronumpy/test/test_base.py

         ulong_dtype = get_dtype_cache(space).w_ulongdtype
         int64_dtype = get_dtype_cache(space).w_int64dtype
         uint64_dtype = get_dtype_cache(space).w_uint64dtype
+        float16_dtype = get_dtype_cache(space).w_float16dtype
         float32_dtype = get_dtype_cache(space).w_float32dtype
         float64_dtype = get_dtype_cache(space).w_float64dtype
 
 
         # Coerce to floats, some of these will eventually be float16, or
         # whatever our smallest float type is.
-        assert find_unaryop_result_dtype(space, bool_dtype, promote_to_float=True) is float32_dtype # will be float16 if we ever put that in
-        assert find_unaryop_result_dtype(space, int8_dtype, promote_to_float=True) is float32_dtype # will be float16 if we ever put that in
-        assert find_unaryop_result_dtype(space, uint8_dtype, promote_to_float=True) is float32_dtype # will be float16 if we ever put that in
+        assert find_unaryop_result_dtype(space, bool_dtype, promote_to_float=True) is float16_dtype 
+        assert find_unaryop_result_dtype(space, int8_dtype, promote_to_float=True) is float16_dtype 
+        assert find_unaryop_result_dtype(space, uint8_dtype, promote_to_float=True) is float16_dtype
         assert find_unaryop_result_dtype(space, int16_dtype, promote_to_float=True) is float32_dtype
         assert find_unaryop_result_dtype(space, uint16_dtype, promote_to_float=True) is float32_dtype
         assert find_unaryop_result_dtype(space, int32_dtype, promote_to_float=True) is float64_dtype

pypy/module/micronumpy/test/test_dtypes.py

     def test_bool_binop_types(self):
         from _numpypy import array, dtype
         types = [
-            '?', 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'f', 'd'
+            '?', 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'f', 'd', 'e',
         ]
         a = array([True], '?')
         for t in types:
             tests.extend([('b','I','l'), ('b','L','d'), ('h','I','l'),
                           ('h','L','d'), ('i','I','l'), ('i','L','d')])
         for d1, d2, dout in tests:
-            assert (array([1], d1) + array([1], d2)).dtype is dtype(dout)
+            # make a failed test print helpful info
+            d3 = (array([1], d1) + array([1], d2)).dtype
+            assert (d1, d2, repr(d3)) == (d1, d2, repr(dtype(dout)))
 
     def test_add_int8(self):
         from _numpypy import array, dtype
             (numpy.int16, 5),
             (numpy.uint32, 7),
             (numpy.int64, 3),
+            (numpy.float16, 10.),
             (numpy.float32, 2.0),
             (numpy.float64, 4.32),
         ]:
         assert numpy.uint64(18446744073709551615) == 18446744073709551615
         raises(OverflowError, numpy.uint64(18446744073709551616))
 
+    def test_float16(self):
+        import _numpypy as numpy
+        assert numpy.float16.mro() == [numpy.float16, numpy.floating, 
+                                       numpy.inexact, numpy.number, 
+                                       numpy.generic, object]
+
+        assert numpy.float16(12) == numpy.float64(12)
+        assert numpy.float16('23.4') == numpy.float16(23.4)
+        raises(ValueError, numpy.float16, '23.2df')
+
+
     def test_float32(self):
         import _numpypy as numpy
 

pypy/module/micronumpy/test/test_numarray.py

         BaseNumpyAppTest.setup_class.im_func(cls)
         cls.w_data = cls.space.wrap(struct.pack('dddd', 1, 2, 3, 4))
         cls.w_fdata = cls.space.wrap(struct.pack('f', 2.3))
+        cls.w_float16val = cls.space.wrap('\x00E') # 5.0 in float16 
         cls.w_float32val = cls.space.wrap(struct.pack('f', 5.2))
         cls.w_float64val = cls.space.wrap(struct.pack('d', 300.4))
         cls.w_ulongval = cls.space.wrap(struct.pack('L', 12))
 
     def test_fromstring_types(self):
         from _numpypy import (fromstring, int8, int16, int32, int64, uint8,
-            uint16, uint32, float32, float64)
-
+            uint16, uint32, float16, float32, float64)
         a = fromstring('\xFF', dtype=int8)
         assert a[0] == -1
         b = fromstring('\xFF', dtype=uint8)
         assert i[0] == float64(300.4)
         j = fromstring(self.ulongval, dtype='L')
         assert j[0] == 12
+        k = fromstring(self.float16val, dtype=float16)
+        assert k[0] == float16(5.)
 
     def test_fromstring_invalid(self):
         from _numpypy import fromstring, uint16, uint8, int32

pypy/module/micronumpy/types.py

 import functools
 import math
-import struct
 
 from pypy.interpreter.error import OperationError
 from pypy.module.micronumpy import interp_boxes
 from pypy.rlib.rawstorage import (alloc_raw_storage, raw_storage_setitem,
                                   raw_storage_getitem)
 from pypy.rlib.objectmodel import specialize
-from pypy.rlib.rarithmetic import widen, byteswap
+from pypy.rlib.rarithmetic import widen, byteswap, r_ulonglong
 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.tool.sourcetools import func_with_new_name
 from pypy.rlib import jit
 from pypy.rlib.rstring import StringBuilder
 
-
 degToRad = math.pi / 180.0
 log2 = math.log(2)
 log2e = 1. / log2
             self._write(storage, i, offset, value)
 
     def runpack_str(self, s):
-        return self.box(runpack(self.format_code, s))
-
-    def pack_str(self, box):
-        return struct.pack(self.format_code, self.unbox(box))
+        v = runpack(self.format_code, s)
+        return self.box(v)
 
     @simple_binary_op
     def add(self, v1, v2):
         value = byteswap(value)
         raw_storage_setitem(storage, i + offset, value)
 
-    def pack_str(self, box):
-        return struct.pack(self.format_code, byteswap(self.unbox(box)))
-
 class Bool(BaseType, Primitive):
     _attrs_ = ()
 
         #value = byteswap(value) XXX
         raw_storage_setitem(storage, i + offset, value)
 
-    def pack_str(self, box):
-        # XXX byteswap
-        return struct.pack(self.format_code, self.unbox(box))
 
+class Float16(BaseType, Float):
+    _attrs_ = ()
+    _STORAGE_T = rffi.USHORT
+    T = rffi.DOUBLE
+
+    BoxType = interp_boxes.W_Float16Box
+
+    def get_element_size(self):
+        return rffi.sizeof(self._STORAGE_T)
+
+    def runpack_str(self, s):
+        assert len(s) == 2
+        fval = unpack_float(s, native_is_bigendian)
+        return self.box(fval)
+
+    def for_computation(self, v):
+        return float(v)
+
+    def default_fromstring(self, space):
+        return self.box(-1.0)
+
+    def _read(self, storage, i, offset):
+        hbits = raw_storage_getitem(self._STORAGE_T, storage, i + offset)
+        return float_unpack(r_ulonglong(hbits), 2)
+
+    def _write(self, storage, i, offset, value):
+        hbits = float_pack(value,2)
+        raw_storage_setitem(storage, i + offset,
+                rffi.cast(self._STORAGE_T, hbits))
+
+class NonNativeFloat16(Float16):
+    _attrs_ = ()
+    BoxType = interp_boxes.W_Float16Box
+
+    def _read(self, storage, i, offset):
+        res = Float16._read(self, storage, i, offset)
+        #return byteswap(res) XXX
+        return res
+
+    def _write(self, storage, i, offset, value):
+        #value = byteswap(value) XXX
+        Float16._write(self, storage, i, offset, value)
 
 class Float32(BaseType, Float):
     _attrs_ = ()

pypy/rlib/rstruct/ieee.py

       - return an int, not a float
       - do round-half-to-even, not round-half-away-from-zero.
 
-    We assume that x is finite and nonnegative; except wrong results
+    We assume that x is finite and nonnegative; expect wrong results
     if you use this for negative x.
 
     """
 
 
 def float_unpack(Q, size):
-    """Convert a 32-bit or 64-bit integer created
+    """Convert a 16-bit, 32-bit or 64-bit integer created
     by float_pack into a Python float."""
 
     if size == 8:
         MAX_EXP = 128    # FLT_MAX_EXP
         MANT_DIG = 24    # FLT_MANT_DIG
         BITS = 32
+    elif size == 2:
+        MIN_EXP = -13   
+        MAX_EXP = 16    
+        MANT_DIG = 11
+        BITS = 16
     else:
         raise ValueError("invalid size value")
 
         MAX_EXP = 128    # FLT_MAX_EXP
         MANT_DIG = 24    # FLT_MANT_DIG
         BITS = 32
+    elif size == 2:
+        MIN_EXP = -13   
+        MAX_EXP = 16    
+        MANT_DIG = 11
+        BITS = 16
     else:
         raise ValueError("invalid size value")
 

pypy/rlib/rstruct/test/test_ieee.py

             if isnan(x):
                 continue
             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:
+            hbit = float_pack(c, 2)
+            assert hbit == h
+            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]]
+        for c,h,f in cases:
+            hbit = float_pack(c, 2)
+            assert hbit == h
+            assert f == float_unpack(h, 2)
+
+    def test_halffloat_overunderflow(self):
+        import math
+        cases = [[670000, float('inf')], [-67000, -float('inf')],
+                 [1e-08, 0], [-1e-8, -0.]]
+        for f1, f2 in cases:
+            try:
+                f_out = float_unpack(float_pack(f1, 2), 2)
+            except OverflowError:
+                f_out = math.copysign(float('inf'), f1)
+            assert f_out == f2
+            assert math.copysign(1., f_out) == math.copysign(1., f2)
+
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.