考虑以下Python代码,它对Python中的复数进行一些简单的算术运算:
import numpy as np
s = 2
l = 5
v = np.array([np.exp(1j*2*np.pi/l)])
A = pow(s*v, l) + s*v
#Print the precision of np.complex128
print np.finfo(np.complex128).precision
#Export using 20 decimal places for real and imaginary parts
np.savetxt('A.csv', A, fmt=['%.20e%+.20ej'], delimiter=',')
我看到这个answer是为了在Python中打印np.complex128
变量的精度,我得到的是15.当我在Spyder中检查A的值时,我看到(32.61803398874989+1.9021130325903035j)
其虚部超过15位小数。此外,导出的CSV文件的值为3.26180339887498931262e+01+1.90211303259030350965e+00j
其实部和虚部都有20个有用的小数位。
我在这里很困惑:如果精度为15,那么额外的小数位数是多少?根据{{3}},np.complex128
由两个64位浮点组成,一个用于实数,一个用于虚部。
但是我的主要问题是我在程序中对复杂的数字(如加法,乘法和矩阵求逆)进行了许多这样的操作,每次运行时我得到的结果不同,有时是正确的,有时是错误的。我的程序似乎对这些操作的准确性非常敏感。如何在Python中量化复杂数字的精确度,我可以拥有的最大值是多少?
我使用的是Python 2.7.14和Numpy 1.14.3。
答案 0 :(得分:0)
完整的答案需要很大的空间。对于初学者,您需要阅读一本关于数值分析的书籍,该书解释了二进制浮点类型如何工作和存储。但这里有一些部分解释。
64位浮点值以二进制形式存储,而不是十进制。因此,关于十进制数字的大部分内容必须是近似值,而不是完整的故事。
当np.finfo(np.complex128).precision
(或其他任何内容)表示有15位有效十进制数字时,表示您不能指望超过这15位数。这是一个从我的IPython控制台获取的示例。
In [4]: 9.000000000000001
Out[4]: 9.000000000000002
In [5]: 9.000000000000001 == 9.000000000000002
Out[5]: True
Python,默认情况下,对任何带小数点的数字使用64位浮点类型,将这两个16位十进制数字视为相同。使用数字9.000000000000001
时,只保证前15个十进制数字正确存储。之后的任何内容都无法保证,在这种情况下,您会看到1
基本上已更改为2
。
有时你可以得到超过那15个十进制数字。例如,由于数字以二进制形式存储,因此1.0
之后的数字会比9.0
更多,而9
之后的数字会比1
更多。这是因为1.9021130325903035
使用4个二进制数字而In [17]: 1.902113032590303 == 1.9021130325903035
Out[17]: False
In [18]: 1.9021130325903036 == 1.9021130325903035
Out[18]: True
In [19]: 1.902113032590304 == 1.9021130325903035
Out[19]: False
仅使用一个,因此在小数点之后可以使用3个二进制数字。因此,让我们看一下您的数字的虚部str
:
repr
我们看到,虽然数字显示17个十进制数字,但当我们将最终数字从5更改为6时,Python看不到任何变化。但如果我们将该数字四舍五入到16位小数,无论是向上还是向下,都会有变化。所以我们可以说数字存储为16位十进制数字和更多。这就是为什么当我解释精度时,我说浮点数保证有15个有效十进制数,但它可能有16,实际精度略高于此。更简单地说,有15或16个有效十进制数字。
Python有两种打印浮点数的基本方法:str
函数和repr
函数。 repr
函数可以简单地打印出来,因此用户可以理解结果,而无需详细说明。 repr
函数提供了更多细节,并尝试打印如此多的细节,以便存储的数据可以完全由打印的内容确定。请注意,1.9021130325903035
在某些情况下是不可见的,例如在控制台中键入数值,或者如您所见,在Spyder中使用变量资源管理器。
当Spyder或Python对您的号码5
执行6
时,它会提供足够的数字来完全定义号码。正如我们在上面看到的,如果它只显示16个十进制数字,丢弃最后的5
,结果将与存储的结果略有不同。因此,Python会打印一个额外的数字,以便您可以知道该值是什么。如果Python打印了最终repr
而不是%.20e
,那么该值将是相同的,但如果Python完全忽略该数字,则该值将被更改。所以Python通过np.savetxt
错误提供太多数字。尽管印有17位数字,但只有16位是确定的。
最后,您的csv文件显示20个十进制数字,因为您告诉Python显示20个十进制数字,这是由于{{1}}命令中的{{1}}说明符所致。尽管你写了什么,那20个十进制数字并不都是“有用的小数位”。根据您定义“有用”的方式,只有前16或17在虚部中有用。 Python基本上将二进制位(全零)添加到存储的值,并打印到20个十进制数字。但是那些零二进制位没有存储在值中。