两个“np.longdouble”的总和产生很大的数值误差

时间:2013-02-14 13:42:01

标签: python numpy long-double

早上好,

我正在读取FITS文件中的两个数字(表示单个数字的整数和浮点部分),将它们转换为长双精度数(我机器中的128位),然后将它们相加。

结果不像我期望的那样使用128位浮点数。这是代码:

a_int = np.longdouble(read_header_key(fits_file, 'I'))
print "I %.25f" % a_int, type(a_int)
a_float = np.longdouble(read_header_key(fits_file, 'F'))
print "F %.25f" % a_float, a_float.dtype
a = a_int + a_float
print "TOT %.25f" % a, a.dtype

这是我得到的答案:

I 55197.0000000000000000000000000 <type 'numpy.float128'>
F 0.0007660185200000000195833 float128
TOT 55197.0007660185219720005989075 float128

结果与我预期的结果不符(55197.0007660185200000000195833)仅为11位小数(总共16位有效数字)。我期望从128位浮点数获得更好的精度。我究竟做错了什么?

此结果在Mac机器和Linux 32位机器上重现(在这种情况下,dtype是float96,但值完全相同)

提前感谢您的帮助!

利玛

2 个答案:

答案 0 :(得分:3)

我的猜测是%f修饰符从你的longdouble对象构造一个float,并在创建格式字符串时使用它。

>>> import numpy as np
>>> np.longdouble(55197)
55197.0
>>> a = np.longdouble(55197)
>>> b = np.longdouble(0.0007660185200000000195833)
>>> a
55197.0
>>> b
0.00076601852000000001958
>>> a + b
55197.00076601852
>>> type(a+b)
<type 'numpy.float128'>
>>> a + b == 55197.00076601852
False

作为旁注,即使repr也没有打印足够的digets来重建对象。这只是因为你不能拥有一个足以传递给longdouble的浮点文字。

答案 1 :(得分:3)

问题在于您打印np.longdouble。使用%f格式化时,Python会在打印前将结果转换为浮点数(64位)。

下面:

>>> a_int = np.longdouble(55197)
>>> a_float = np.longdouble(76601852) / 10**11
>>> b = a_int + a_float
>>> '%.25f' % b
'55197.0007660185219720005989075'
>>> '%.25f' % float(b)
'55197.0007660185219720005989075'
>>> b * 10**18
5.5197000766018519998e+22

请注意,在我的机器上,longdouble与普通double相比,我只能获得更高的精度(20位小数而不是15位)。因此,可能值得看看Decimal模块是否更适合您的应用程序。 Decimal处理任意精度的十进制浮点数而不会损失精度。