Author: Maciej Fijalkowski <[email protected]>
Branch:
Changeset: r59589:91085896a136
Date: 2012-12-27 20:24 +0200
http://bitbucket.org/pypy/pypy/changeset/91085896a136/
Log: (mattip) merge numpypy-longdouble, this adds longdouble, longfloat
and clongdouble (I think :) as dtypes
diff --git a/pypy/module/micronumpy/__init__.py
b/pypy/module/micronumpy/__init__.py
--- a/pypy/module/micronumpy/__init__.py
+++ b/pypy/module/micronumpy/__init__.py
@@ -1,4 +1,5 @@
from pypy.interpreter.mixedmodule import MixedModule
+from pypy.module.micronumpy.interp_boxes import long_double_size
class Module(MixedModule):
@@ -58,6 +59,8 @@
'float16': 'interp_boxes.W_Float16Box',
'float32': 'interp_boxes.W_Float32Box',
'float64': 'interp_boxes.W_Float64Box',
+ 'longdouble': 'interp_boxes.W_LongDoubleBox',
+ 'longfloat': 'interp_boxes.W_LongDoubleBox',
'intp': 'types.IntP.BoxType',
'uintp': 'types.UIntP.BoxType',
'flexible': 'interp_boxes.W_FlexibleBox',
@@ -70,6 +73,8 @@
'complex_': 'interp_boxes.W_Complex128Box',
'complex128': 'interp_boxes.W_Complex128Box',
'complex64': 'interp_boxes.W_Complex64Box',
+ 'clongdouble': 'interp_boxes.W_CLongDoubleBox',
+ 'clongfloat': 'interp_boxes.W_CLongDoubleBox',
}
# ufuncs
@@ -163,3 +168,10 @@
'max': 'app_numpy.max',
'arange': 'app_numpy.arange',
}
+
+if long_double_size == 16:
+ Module.interpleveldefs['float128'] = 'interp_boxes.W_Float128Box'
+ Module.interpleveldefs['complex256'] = 'interp_boxes.W_Complex256Box'
+elif long_double_size == 12:
+ Module.interpleveldefs['float96'] = 'interp_boxes.W_Float96Box'
+ Module.interpleveldefs['complex192'] = 'interp_boxes.W_Complex192Box'
diff --git a/pypy/module/micronumpy/interp_boxes.py
b/pypy/module/micronumpy/interp_boxes.py
--- a/pypy/module/micronumpy/interp_boxes.py
+++ b/pypy/module/micronumpy/interp_boxes.py
@@ -8,12 +8,20 @@
from pypy.objspace.std.inttype import int_typedef
from pypy.objspace.std.complextype import complex_typedef
from pypy.rlib.rarithmetic import LONG_BIT
+from pypy.rpython.lltypesystem import rffi
from pypy.tool.sourcetools import func_with_new_name
from pypy.module.micronumpy.arrayimpl.voidbox import VoidBoxStorage
MIXIN_32 = (int_typedef,) if LONG_BIT == 32 else ()
MIXIN_64 = (int_typedef,) if LONG_BIT == 64 else ()
+# Is this the proper place for this?
+long_double_size = rffi.sizeof_c_type('long double', ignore_errors=True)
+import os
+if long_double_size == 8 and os.name == 'nt':
+ # this is a lie, or maybe a wish
+ long_double_size = 12
+
def new_dtype_getter(name):
def _get_dtype(space):
@@ -226,7 +234,6 @@
class W_Float64Box(W_FloatingBox, PrimitiveBox):
descr__new__, _get_dtype = new_dtype_getter("float64")
-
class W_FlexibleBox(W_GenericBox):
def __init__(self, arr, ofs, dtype):
self.arr = arr # we have to keep array alive
@@ -315,6 +322,33 @@
descr__new__, _get_dtype = new_dtype_getter("complex128")
_COMPONENTS_BOX = W_Float64Box
+if long_double_size == 12:
+ class W_Float96Box(W_FloatingBox, PrimitiveBox):
+ descr__new__, _get_dtype = new_dtype_getter("float96")
+
+ W_LongDoubleBox = W_Float96Box
+
+ class W_Complex192Box(ComplexBox, W_ComplexFloatingBox):
+ descr__new__, _get_dtype = new_dtype_getter("complex192")
+ _COMPONENTS_BOX = W_Float96Box
+
+ W_CLongDoubleBox = W_Complex192Box
+
+elif long_double_size == 16:
+ class W_Float128Box(W_FloatingBox, PrimitiveBox):
+ descr__new__, _get_dtype = new_dtype_getter("float128")
+ W_LongDoubleBox = W_Float128Box
+
+ class W_Complex256Box(ComplexBox, W_ComplexFloatingBox):
+ descr__new__, _get_dtype = new_dtype_getter("complex256")
+ _COMPONENTS_BOX = W_Float128Box
+
+ W_CLongDoubleBox = W_Complex256Box
+
+else:
+ W_LongDoubleBox = W_Float64Box
+ W_CLongDoubleBox = W_Complex64Box
+
W_GenericBox.typedef = TypeDef("generic",
__module__ = "numpypy",
@@ -479,6 +513,33 @@
__new__ = interp2app(W_Float64Box.descr__new__.im_func),
)
+if long_double_size == 12:
+ W_Float96Box.typedef = TypeDef("float96", (W_FloatingBox.typedef),
+ __module__ = "numpypy",
+
+ __new__ = interp2app(W_Float96Box.descr__new__.im_func),
+ )
+
+ W_Complex192Box.typedef = TypeDef("complex192",
(W_ComplexFloatingBox.typedef, complex_typedef),
+ __module__ = "numpypy",
+ __new__ = interp2app(W_Complex192Box.descr__new__.im_func),
+ real = GetSetProperty(W_ComplexFloatingBox.descr_get_real),
+ imag = GetSetProperty(W_ComplexFloatingBox.descr_get_imag),
+ )
+
+elif long_double_size == 16:
+ W_Float128Box.typedef = TypeDef("float128", (W_FloatingBox.typedef),
+ __module__ = "numpypy",
+
+ __new__ = interp2app(W_Float128Box.descr__new__.im_func),
+ )
+
+ W_Complex256Box.typedef = TypeDef("complex256",
(W_ComplexFloatingBox.typedef, complex_typedef),
+ __module__ = "numpypy",
+ __new__ = interp2app(W_Complex256Box.descr__new__.im_func),
+ real = GetSetProperty(W_ComplexFloatingBox.descr_get_real),
+ imag = GetSetProperty(W_ComplexFloatingBox.descr_get_imag),
+ )
W_FlexibleBox.typedef = TypeDef("flexible", W_GenericBox.typedef,
__module__ = "numpypy",
diff --git a/pypy/module/micronumpy/interp_dtype.py
b/pypy/module/micronumpy/interp_dtype.py
--- a/pypy/module/micronumpy/interp_dtype.py
+++ b/pypy/module/micronumpy/interp_dtype.py
@@ -15,6 +15,7 @@
SIGNEDLTR = "i"
BOOLLTR = "b"
FLOATINGLTR = "f"
+COMPLEXLTR = "c"
VOIDLTR = 'V'
STRINGLTR = 'S'
UNICODELTR = 'U'
@@ -135,7 +136,7 @@
return self.kind == SIGNEDLTR
def is_complex_type(self):
- return (self.num == 14 or self.num == 15)
+ return (self.num == 14 or self.num == 15 or self.num == 16)
def is_bool_type(self):
return self.kind == BOOLLTR
@@ -412,17 +413,10 @@
alternate_constructors=[space.w_float],
aliases=["float"],
)
- # self.w_float128dtype = W_Dtype(
- # types.Float128(),
- # num=13,
- # kind=FLOATINGLTR,
- # name="float128",
- # ...
- # )
self.w_complex64dtype = W_Dtype(
types.Complex64(),
num=14,
- kind=FLOATINGLTR,
+ kind=COMPLEXLTR,
name="complex64",
char="F",
w_box_type = space.gettypefor(interp_boxes.W_Complex64Box),
@@ -430,13 +424,64 @@
self.w_complex128dtype = W_Dtype(
types.Complex128(),
num=15,
- kind=FLOATINGLTR,
+ kind=COMPLEXLTR,
name="complex128",
char="D",
w_box_type = space.gettypefor(interp_boxes.W_Complex128Box),
alternate_constructors=[space.w_complex],
aliases=["complex"],
)
+ if interp_boxes.long_double_size == 12:
+ self.w_float96dtype = W_Dtype(
+ types.Float96(),
+ num=13,
+ kind=FLOATINGLTR,
+ name="float96",
+ char="g",
+ w_box_type=space.gettypefor(interp_boxes.W_Float96Box),
+ aliases=["longfloat", "longdouble"],
+ )
+ self.w_longdouble = self.w_float96dtype
+
+ self.w_complex192dtype = W_Dtype(
+ types.Complex192(),
+ num=16,
+ kind=COMPLEXLTR,
+ name="complex192",
+ char="G",
+ w_box_type = space.gettypefor(interp_boxes.W_Complex192Box),
+ alternate_constructors=[space.w_complex],
+ aliases=["clongdouble", "clongfloat"],
+ )
+ self.w_clongdouble = self.w_complex192dtype
+
+ elif interp_boxes.long_double_size == 16:
+ self.w_float128dtype = W_Dtype(
+ types.Float128(),
+ num=13,
+ kind=FLOATINGLTR,
+ name="float128",
+ char="g",
+ w_box_type=space.gettypefor(interp_boxes.W_Float128Box),
+ aliases=["longfloat", "longdouble"],
+ )
+ self.w_longdouble = self.w_float128dtype
+
+ self.w_complex256dtype = W_Dtype(
+ types.Complex256(),
+ num=16,
+ kind=COMPLEXLTR,
+ name="complex256",
+ char="G",
+ w_box_type = space.gettypefor(interp_boxes.W_Complex256Box),
+ alternate_constructors=[space.w_complex],
+ aliases=["clongdouble", "clongfloat"],
+ )
+ self.w_clongdouble = self.w_complex256dtype
+ else:
+ self.w_float64dtype.aliases += ["longfloat", "longdouble"]
+ self.w_longdouble = self.w_float64dtype
+ self.w_clongdouble = self.w_complex64dtype
self.w_stringdtype = W_Dtype(
types.StringType(1),
num=18,
@@ -507,14 +552,16 @@
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_float16dtype, self.w_float32dtype, self.w_float64dtype,
self.w_complex64dtype,
- self.w_complex128dtype,
+ self.w_float16dtype, self.w_float32dtype, self.w_float64dtype,
+ self.w_longdouble,
+ self.w_complex64dtype, self.w_complex128dtype, self.w_clongdouble,
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_float16dtype, self.w_float32dtype,
self.w_float64dtype]
+ for dtype in [self.w_float16dtype, self.w_float32dtype,
+ self.w_float64dtype, self.w_longdouble]
)
self.dtypes_by_name = {}
# we reverse, so the stuff with lower numbers override stuff with
@@ -540,7 +587,7 @@
'LONGLONG': self.w_int64dtype,
'SHORT': self.w_int16dtype,
'VOID': self.w_voiddtype,
- #'LONGDOUBLE':,
+ 'LONGDOUBLE': self.w_longdouble,
'UBYTE': self.w_uint8dtype,
'UINTP': self.w_ulongdtype,
'ULONG': self.w_ulongdtype,
@@ -549,7 +596,7 @@
#'OBJECT',
'ULONGLONG': self.w_uint64dtype,
'STRING': self.w_stringdtype,
- #'CDOUBLE',
+ 'CDOUBLE': self.w_complex64dtype,
#'DATETIME',
'UINT': self.w_uint32dtype,
'INTP': self.w_intpdtype,
@@ -563,7 +610,7 @@
'USHORT': self.w_uint16dtype,
'FLOAT': self.w_float32dtype,
'BOOL': self.w_booldtype,
- #, 'CLONGDOUBLE']
+ 'CLONGDOUBLE': self.w_clongdouble,
}
typeinfo_partial = {
'Generic': interp_boxes.W_GenericBox,
@@ -573,7 +620,7 @@
'Integer': interp_boxes.W_IntegerBox,
'SignedInteger': interp_boxes.W_SignedIntegerBox,
'UnsignedInteger': interp_boxes.W_UnsignedIntegerBox,
- #'ComplexFloating',
+ 'ComplexFloating': interp_boxes.W_ComplexFloatingBox,
'Number': interp_boxes.W_NumberBox,
'Floating': interp_boxes.W_FloatingBox
}
diff --git a/pypy/module/micronumpy/interp_ufuncs.py
b/pypy/module/micronumpy/interp_ufuncs.py
--- a/pypy/module/micronumpy/interp_ufuncs.py
+++ b/pypy/module/micronumpy/interp_ufuncs.py
@@ -375,12 +375,17 @@
if promote_bools and (dt1.kind == dt2.kind == interp_dtype.BOOLLTR):
return interp_dtype.get_dtype_cache(space).w_int8dtype
- # Everything promotes to complex
- if dt2.num == 14 or dt2.num == 15 or dt1.num == 14 or dt2.num == 15:
- if dt2.num == 15 or dt1.num == 15:
+ # Everything numeric promotes to complex
+ if dt2.is_complex_type() or dt1.is_complex_type():
+ if dt2.num == 14:
+ return interp_dtype.get_dtype_cache(space).w_complex64dtype
+ elif dt2.num == 15:
return interp_dtype.get_dtype_cache(space).w_complex128dtype
+ elif dt2.num == 16:
+ return interp_dtype.get_dtype_cache(space).w_clongdouble
else:
- return interp_dtype.get_dtype_cache(space).w_complex64dtype
+ raise OperationError(space.w_TypeError, space.wrap("Unsupported
types"))
+
if promote_to_float:
return find_unaryop_result_dtype(space, dt2, promote_to_float=True)
@@ -431,7 +436,7 @@
if not allow_complex and (dt.is_complex_type()):
raise OperationError(space.w_TypeError, space.wrap("Unsupported
types"))
if promote_to_float:
- if dt.kind == interp_dtype.FLOATINGLTR:
+ if dt.kind == interp_dtype.FLOATINGLTR or
dt.kind==interp_dtype.COMPLEXLTR:
return dt
if dt.num >= 5:
return interp_dtype.get_dtype_cache(space).w_float64dtype
diff --git a/pypy/module/micronumpy/test/test_complex.py
b/pypy/module/micronumpy/test/test_complex.py
--- a/pypy/module/micronumpy/test/test_complex.py
+++ b/pypy/module/micronumpy/test/test_complex.py
@@ -139,7 +139,6 @@
def test_fmax(self):
from _numpypy import fmax, array
- import math
nnan, nan, inf, ninf = float('-nan'), float('nan'), float('inf'),
float('-inf')
a = array((complex(ninf, 10), complex(10, ninf),
complex( inf, 10), complex(10, inf),
@@ -167,7 +166,6 @@
def test_fmin(self):
from _numpypy import fmin, array
- import math
nnan, nan, inf, ninf = float('-nan'), float('nan'), float('inf'),
float('-inf')
a = array((complex(ninf, 10), complex(10, ninf),
complex( inf, 10), complex(10, inf),
@@ -198,7 +196,7 @@
raises(TypeError, signbit, complex(1,1))
def test_reciprocal(self):
- from _numpypy import array, reciprocal, complex64, complex128
+ from _numpypy import array, reciprocal, complex64, complex128,
clongdouble
inf = float('inf')
nan = float('nan')
@@ -214,7 +212,7 @@
complex(-r, i),
-0j, 0j, cnan,
cnan, cnan, cnan]
- for c, rel_err in ((complex64, 2e-7), (complex128, 2e-15), ):
+ for c, rel_err in ((complex64, 2e-7), (complex128, 2e-15),
(clongdouble, 2e-15)):
actual = reciprocal(array([orig], dtype=c))
for b, a, e in zip(orig, actual, expected):
assert (a[0].real - e.real) < rel_err
@@ -234,13 +232,12 @@
raises(TypeError, copysign, a, b)
def test_exp2(self):
- import math
- from _numpypy import array, exp2, complex128, complex64
+ from _numpypy import array, exp2, complex128, complex64, clongfloat
inf = float('inf')
ninf = -float('inf')
nan = float('nan')
cmpl = complex
- for c,rel_err in ((complex128, 2e-15), (complex64, 1e-7)):
+ for c,rel_err in ((complex128, 2e-15), (complex64, 1e-7), (clongfloat,
2e-15)):
a = [cmpl(-5., 0), cmpl(-5., -5.), cmpl(-5., 5.),
cmpl(0., -5.), cmpl(0., 0.), cmpl(0., 5.),
cmpl(-0., -5.), cmpl(-0., 0.), cmpl(-0., 5.),
@@ -499,7 +496,7 @@
def test_basic(self):
from _numpypy import (complex128, complex64, add, array, dtype,
subtract as sub, multiply, divide, negative, abs, floor_divide,
- real, imag, sign)
+ real, imag, sign, clongfloat)
from _numpypy import (equal, not_equal, greater, greater_equal, less,
less_equal, isnan)
assert real(4.0) == 4.0
@@ -507,7 +504,7 @@
a = array([complex(3.0, 4.0)])
b = a.real
assert b.dtype == dtype(float)
- for complex_ in complex64, complex128:
+ for complex_ in complex64, complex128, clongfloat:
O = complex(0, 0)
c0 = complex_(complex(2.5, 0))
diff --git a/pypy/module/micronumpy/test/test_dtypes.py
b/pypy/module/micronumpy/test/test_dtypes.py
--- a/pypy/module/micronumpy/test/test_dtypes.py
+++ b/pypy/module/micronumpy/test/test_dtypes.py
@@ -116,8 +116,11 @@
def test_bool_binop_types(self):
from _numpypy import array, dtype
types = [
- '?', 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'f', 'd',
'e',
+ '?', 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'f', 'd',
+ 'e'
]
+ if array([0], dtype='longdouble').itemsize > 8:
+ types += ['g', 'G']
a = array([True], '?')
for t in types:
assert (a + array([0], t)).dtype is dtype(t)
@@ -233,6 +236,7 @@
(numpy.float16, 10.),
(numpy.float32, 2.0),
(numpy.float64, 4.32),
+ (numpy.longdouble, 4.32),
]:
assert hash(tp(value)) == hash(value)
@@ -469,6 +473,19 @@
assert numpy.float64('23.4') == numpy.float64(23.4)
raises(ValueError, numpy.float64, '23.2df')
+ def test_longfloat(self):
+ import _numpypy as numpy
+ # it can be float96 or float128
+ if numpy.longfloat != numpy.float64:
+ assert numpy.longfloat.mro()[1:] == [numpy.floating,
+ numpy.inexact, numpy.number,
+ numpy.generic, object]
+ a = numpy.array([1, 2, 3], numpy.longdouble)
+ assert repr(type(a[1])) == repr(numpy.longdouble)
+ assert numpy.float64(12) == numpy.longdouble(12)
+ assert numpy.float64(12) == numpy.longfloat(12)
+ raises(ValueError, numpy.longfloat, '23.2df')
+
def test_complex_floating(self):
import _numpypy as numpy
@@ -526,6 +543,12 @@
assert numpy.dtype(complex).type is numpy.complex128
assert numpy.dtype("complex").type is numpy.complex128
+ d = numpy.dtype('complex64')
+ assert d.kind == 'c'
+ assert d.num == 14
+ assert d.char == 'F'
+
+
def test_subclass_type(self):
import _numpypy as numpy
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
@@ -2110,7 +2110,7 @@
def test_fromstring_types(self):
from _numpypy import (fromstring, int8, int16, int32, int64, uint8,
- uint16, uint32, float16, float32, float64)
+ uint16, uint32, float16, float32, float64, longfloat, array)
a = fromstring('\xFF', dtype=int8)
assert a[0] == -1
b = fromstring('\xFF', dtype=uint8)
@@ -2133,9 +2133,21 @@
assert j[0] == 12
k = fromstring(self.float16val, dtype=float16)
assert k[0] == float16(5.)
+ dt = array([5],dtype=longfloat).dtype
+ if dt.itemsize == 12:
+ from _numpypy import float96
+ 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@\x00\x00\x00\x00\x00\x00',
dtype=float128)
+ elif dt.itemsize == 8:
+ skip('longfloat is float64')
+ else:
+ skip('unknown itemsize for longfloat')
+ 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
@@ -1496,7 +1497,6 @@
ComponentBoxType = interp_boxes.W_Float32Box
-
NonNativeComplex64 = Complex64
class Complex128(ComplexFloating, BaseType):
@@ -1510,6 +1510,60 @@
NonNativeComplex128 = Complex128
+if interp_boxes.long_double_size == 12:
+ class Float96(BaseType, Float):
+ _attrs_ = ()
+
+ T = rffi.LONGDOUBLE
+ BoxType = interp_boxes.W_Float96Box
+ format_code = "q"
+
+ def runpack_str(self, s):
+ assert len(s) == 12
+ fval = unpack_float128(s, native_is_bigendian)
+ return self.box(fval)
+
+ class NonNativeFloat96(Float96):
+ pass
+
+ class Complex192(ComplexFloating, BaseType):
+ _attrs_ = ()
+
+ T = rffi.CHAR
+ _COMPONENTS_T = rffi.LONGDOUBLE
+ BoxType = interp_boxes.W_Complex192Box
+ ComponentBoxType = interp_boxes.W_Float96Box
+
+ NonNativeComplex192 = Complex192
+
+
+elif interp_boxes.long_double_size == 16:
+ class Float128(BaseType, Float):
+ _attrs_ = ()
+
+ T = rffi.LONGDOUBLE
+ BoxType = interp_boxes.W_Float128Box
+ format_code = "q"
+
+ def runpack_str(self, s):
+ assert len(s) == 16
+ fval = unpack_float128(s, native_is_bigendian)
+ return self.box(fval)
+
+ class NonNativeFloat128(Float128):
+ pass
+
+ class Complex256(ComplexFloating, BaseType):
+ _attrs_ = ()
+
+ T = rffi.CHAR
+ _COMPONENTS_T = rffi.LONGDOUBLE
+ BoxType = interp_boxes.W_Complex256Box
+ ComponentBoxType = interp_boxes.W_Float128Box
+
+
+ NonNativeComplex256 = Complex256
+
class BaseStringType(object):
_mixin_ = True
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,11 +25,90 @@
int_part += 1
return int_part
+def float_unpack80(QQ):
+ '''Unpack a (mant, exp) tuple of r_ulonglong in 80-bit extended format
+ into a long double float
+ '''
+ MIN_EXP = -16381
+ MAX_EXP = 16384
+ MANT_DIG = 64
+ TOPBITS = 80 - 64
+ one = r_ulonglong(1)
+ if len(QQ) != 2:
+ raise ValueError("QQ must be two 64 bit uints")
+ 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 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[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
+ result = rfloat.NAN if mant &((one << MANT_DIG - 1) - 1) else
rfloat.INFINITY
+ 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 or 64-bit integer created
+ """Convert a 16-bit, 32-bit 64-bit integer created
by float_pack into a Python float."""
+ 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
+ BITS = 64
+ one = r_ulonglong(1)
+ elif size == 4:
+ MIN_EXP = -125 # C's FLT_MIN_EXP
+ MAX_EXP = 128 # FLT_MAX_EXP
+ MANT_DIG = 24 # FLT_MANT_DIG
+ BITS = 32
+ one = r_ulonglong(1)
+ elif size == 2:
+ MIN_EXP = -13
+ MAX_EXP = 16
+ MANT_DIG = 11
+ BITS = 16
+ one = r_ulonglong(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 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)
+
+ 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: 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
+
+
+def float_pack(x, size):
+ """Convert a Python float x into a 64-bit unsigned integer
+ with the same byte representation."""
if size == 8:
MIN_EXP = -1021 # = sys.float_info.min_exp
MAX_EXP = 1024 # = sys.float_info.max_exp
@@ -45,54 +124,13 @@
MAX_EXP = 16
MANT_DIG = 11
BITS = 16
- 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 out of range")
-
- # extract pieces
- one = r_ulonglong(1)
- 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)
-
- 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
- mant += one << MANT_DIG - 1
- result = math.ldexp(mant, exp + MIN_EXP - MANT_DIG - 1)
- return -result if sign else result
-
-
-def float_pack(x, size):
- """Convert a Python float x into a 64-bit unsigned integer
- with the same byte representation."""
-
- 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
- BITS = 64
- elif size == 4:
- MIN_EXP = -125 # C's FLT_MIN_EXP
- 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
+ elif 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")
@@ -139,26 +177,97 @@
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_ulonglong(1) <<(MANT_DIG-1) #1 is explicit for 80bit
extended format
+ exp = exp << 1
exp = r_ulonglong(exp)
sign = r_ulonglong(sign)
return ((sign << BITS - 1) | (exp << MANT_DIG - 1)) | mant
+def float_pack80(x):
+ """Convert a Python float x into two 64-bit unsigned integers
+ with 80 bit extended representation."""
+ MIN_EXP = -16381
+ MAX_EXP = 16384
+ MANT_DIG = 64
+ BITS = 80
+
+ 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)) - 1 # 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
+ 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):
l = []
- unsigned = float_pack(x, size)
- for i in range(size):
- l.append(chr((unsigned >> (i * 8)) & 0xFF))
+ if size == 12 or size == 16:
+ unsigned = float_pack80(x)
+ for i in range(8):
+ l.append(chr((unsigned[0] >> (i * 8)) & 0xFF))
+ for i in range(size - 8):
+ l.append(chr((unsigned[1] >> (i * 8)) & 0xFF))
+ else:
+ unsigned = float_pack(x, size)
+ for i in range(size):
+ l.append(chr((unsigned >> (i * 8)) & 0xFF))
if be:
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):
+ QQ = [r_ulonglong(0), r_ulonglong(0)]
+ for i in range(8):
+ c = ord(s[len(s) - 1 - i if be else i])
+ QQ[0] |= r_ulonglong(c) << (i * 8)
+ for i in range(8, len(s)):
+ c = ord(s[len(s) - 1 - i if be else i])
+ QQ[1] |= r_ulonglong(c) << ((i - 8) * 8)
+ return float_unpack80(QQ)
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
+from pypy.rlib.rstruct.ieee import float_pack, float_unpack, float_pack80,
float_unpack80
class TestFloatPacking:
@@ -18,6 +18,10 @@
y = float_unpack(Q, 8)
assert repr(x) == repr(y)
+ Q = float_pack80(x)
+ y = float_unpack80(Q)
+ 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]
float_pack8 = float_pack(x, 8)
@@ -34,10 +38,20 @@
float_pack4 = "overflow"
assert struct_pack4 == float_pack4
+ if float_pack4 == "overflow":
+ return
+
# if we didn't overflow, try round-tripping the binary32 value
- if float_pack4 != "overflow":
- roundtrip = float_pack(float_unpack(float_pack4, 4), 4)
- assert float_pack4 == roundtrip
+ roundtrip = float_pack(float_unpack(float_pack4, 4), 4)
+ assert float_pack4 == roundtrip
+
+ try:
+ float_pack2 = float_pack(x, 2)
+ except OverflowError:
+ return
+
+ roundtrip = float_pack(float_unpack(float_pack2, 2), 2)
+ assert (float_pack2,x) == (roundtrip,x)
def test_infinities(self):
self.check_float(float('inf'))
@@ -48,12 +62,18 @@
self.check_float(-0.0)
def test_nans(self):
+ Q = float_pack80(float('nan'))
+ y = float_unpack80(Q)
+ assert repr(y) == 'nan'
Q = float_pack(float('nan'), 8)
y = float_unpack(Q, 8)
assert repr(y) == 'nan'
L = float_pack(float('nan'), 4)
z = float_unpack(L, 4)
assert repr(z) == 'nan'
+ L = float_pack(float('nan'), 2)
+ z = float_unpack(L, 2)
+ assert repr(z) == 'nan'
def test_simple(self):
test_values = [1e-10, 0.00123, 0.5, 0.7, 1.0, 123.456, 1e10]
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit