我一直在玩C99 quad precision长双。据我所知,(平台特定的)numpy支持long double和128bit浮点数。
我遇到了一些我无法解释的事情。
假设:
>>> import numpy as np
计算一个需要64位以上但小于128位的数字来表示整数:
>>> 2**64+2
18446744073709551618 # note the '8' at the end
>>> int(2**64+2)
18446744073709551618 # same obviously
如果我calculate在C99 128位长双倍中使用相同的数字,我会得到18446744073709551618.000000
现在,如果我使用numpy long double:
>>> a=np.longdouble(2)
>>> b=np.longdouble(64)
>>> a**b+a
18446744073709551618.0 # all good...
这些不正确的结果如何:
>>> np.longdouble(2**64+2)
18446744073709551616.0 # Note '6'; appears 2**64 not done in long double
>>> np.longdouble(int(2**64+2))
18446744073709551616.0 # can't force the use of a Python long
>>> n=int(2**64+2)
>>> np.longdouble(n)
18446744073709551616.0
>>> np.longdouble(18446744073709551618)
18446744073709551616.0 # It really does not want to do '8' at the end
但是,这有效:
>>> np.longdouble(2**64)+2
18446744073709551618.0
问题:numpy是否存在将值正确转换为长双打的问题?有什么我做错了吗?
答案 0 :(得分:10)
您正尝试在非直接可转换类型之间执行类型转换。看看堆栈:
#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
如您所见,Python long
(无限精度整数)2**64 + 2
正在转换为float
(即64位双精度),这会失去精度;然后使用float初始化long double,但精度已经丢失。
问题是128位double不是本机Python类型,因此long
没有本机转换,只有64位double。 NumPy可能有可能检测到这种情况并使用long
C API执行自己的转换,但可能相对较少的好处相当复杂(您可以从一开始就在np.longdouble
进行算术运算)。
答案 1 :(得分:2)
NumPy在x86机器上不提供四倍精度。它确实提供了对C long double类型的访问(由编译环境提供;对于MSVC,这可能是64位,GCC通常是80位)作为np.longdouble。类型np.float96和np.float128只是填充到96或128位的长双精度数(用于对齐的内存访问)。见the numpy docs。要获得numpy的四倍精度,你需要使用硬件平台和编译器,其中long double是实际的四倍精度。
虽然numpy可以使用编译器支持(GCC的 float128 )或外部库来支持四倍精度,但这还没有实现。也可以编写第三方可导入模块,使其中一个可用,但尚未完成。
另请注意,即使使用np.longdouble,也很容易丢失精度:例如,%运算符强制numpy通过python浮点数传递其数字,从而丢掉任何额外的精度。