Numpy longdouble arithmetic does not seem to be in long double with conversion

后端 未结 2 1762
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-12-18 22:48

I have been playing C99\'s quad precision long double. It is my understanding that (platform specific) numpy supports long double and 128bit floats.

I have run acro

相关标签:
2条回答
  • 2020-12-18 23:38

    NumPy does not provide quad precision on x86 machines. It does provide access to the C long double type (as provided by the compilation environment; with MSVC this may be 64 bits, with GCC it is normally 80 bits) as np.longdouble. The types np.float96 and np.float128 are simply long doubles padded to 96 or 128 bits (for aligned memory access). See the numpy docs. To get quad precision in numpy you need to use a hardware platform and compiler where long double is actual quad precision.

    While it would be possible for numpy to support quad precision using compiler support (GCC's float128) or external libraries, this has not been implemented. It would also be possible to write a third-party importable module that made one of these available, but that has not been done either.

    Note too that even when using np.longdouble, it is easy to lose precision: for example, the % operator forces numpy to pass its numbers through python floats, throwing away any extra precision.

    0 讨论(0)
  • 2020-12-18 23:42

    You're trying to perform a type conversion between non-directly-convertible types. Take a look at the stack:

    #0  0x00002aaaaab243a0 in PyLong_AsDouble ()
       from libpython2.7.so.1.0
    #1  0x00002aaaaab2447a in ?? ()
       from libpython2.7.so.1.0
    #2  0x00002aaaaaaf8357 in PyNumber_Float ()
       from libpython2.7.so.1.0
    #3  0x00002aaaae71acdc in MyPyFloat_AsDouble (obj=0x2aaaaae93c00)
        at numpy/core/src/multiarray/arraytypes.c.src:40
    #4  0x00002aaaae71adfc in LONGDOUBLE_setitem (op=0x2aaaaae93c00, 
        ov=0xc157b0 "", ap=0xbf6ca0)
        at numpy/core/src/multiarray/arraytypes.c.src:278
    #5  0x00002aaaae705c82 in PyArray_FromAny (op=0x2aaaaae93c00, 
        newtype=0x2aaaae995960, min_depth=<value optimized out>, max_depth=0, 
        flags=0, context=<value optimized out>)
        at numpy/core/src/multiarray/ctors.c:1664
    #6  0x00002aaaae7300ad in longdouble_arrtype_new (type=0x2aaaae9938a0, 
        args=<value optimized out>, __NPY_UNUSED_TAGGEDkwds=<value optimized out>)
        at numpy/core/src/multiarray/scalartypes.c.src:2545
    

    As you can see, the Python long (unlimited-precision integer) 2**64 + 2 is being converted to float (i.e. 64-bit double), which loses precision; the float is then used to initialise the long double but the precision has already been lost.

    The problem is that 128-bit double is not a native Python type, so long doesn't have a native conversion to it, only to 64-bit double. It probably would be possible for NumPy to detect this situation and perform its own conversion using the long C API, but might be fairly complicated for relatively little benefit (you can just do arithmetic in np.longdouble from the start).

    0 讨论(0)
提交回复
热议问题