复数的 Numpy 小数点精度
Numpy decimal points precision of complex numbers
考虑以下 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,那些多余的小数位是多少?根据here,np.complex128
由两个64位的浮点数组成,一个是实部,一个是虚部。
但我的主要问题是,我在程序中对复数(如加法、乘法和矩阵求逆)进行了许多此类运算,每次 运行 都会得到不同的结果,有时是正确的,有时是错误的。看来我的程序对这些操作的准确性非常敏感。 Python 中复数的精度是如何量化的?我能达到的最大值是多少?
我正在使用 Python 2.7.14 和 Numpy 1.14.3。
完整的答案需要很多 space。对于初学者,您需要阅读一本关于数值分析的书,该书解释了二进制浮点类型的工作和存储方式。但这里有一些部分的解释。
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
的数字在 radix point 之后的二进制数字将比 9.0
这样的数字多。这是因为9
使用了4位二进制数,而1
只使用了1位,所以小数点后可以再使用3位二进制数。那么让我们看看你的数字的虚部,1.9021130325903035
:
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
我们看到,虽然数字显示 17 位十进制数字,但当我们将最后一位数字从 5 更改为 6 时,Python 没有看到任何变化。但是,如果我们将该数字向上或向下舍入为 16 位十进制数字,则会发生变化。所以我们可以说该数字存储为 16 位十进制数字甚至更多。这就是为什么当我解释精度时,我说浮点数保证有 15 位有效小数位,但它可能有 16 位,而实际精度略高于此。更简单地说,有 15 或 16 位有效的小数位。
Python 有两种打印浮点数的基本方法:str
函数和 repr
函数。 str
函数打印内容很简单,因此用户无需深入了解细节即可理解结果。 repr
函数给出了更多的细节,并试图打印如此多的细节,以至于存储的数据可以完全由打印的内容决定。请注意,repr
在某些情况下是不可见的,例如在控制台中键入数值,或者如您所见,在 Spyder 中使用变量资源管理器。
当 Spyder 或 Python 对您的号码 1.9021130325903035
执行 repr
时,它会提供足够的数字来完整定义号码。正如我们在上面看到的,如果它只显示 16 位十进制数字,去掉最后的 5
,结果将与存储的略有不同。因此 Python 打印了一个额外的数字,这样你就可以知道这个值是多少。如果 Python 打印了最后的 6
而不是 5
,则值将是相同的,但如果 Python 完全省略了该数字,则该值将被更改。所以 Python 通过 repr
错误的是给了太多数字。尽管打印了 17 个数字,但其中只有 16 个数字是确定的。
最后,由于 np.savetxt
命令中的 %.20e
说明符,您的 csv 文件显示了 20 个十进制数字,因为您告诉 Python 显示 20 个十进制数字。这 20 位小数并不都是“有用的 小数位”,不管你写了什么。只有前 16 或 17 个在虚数部分有用,具体取决于您如何定义 "useful." Python 基本上是将二进制位全零添加到存储值,并将其打印为 20 位十进制数字。但是那些零二进制位没有存储在值中。
考虑以下 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,那些多余的小数位是多少?根据here,np.complex128
由两个64位的浮点数组成,一个是实部,一个是虚部。
但我的主要问题是,我在程序中对复数(如加法、乘法和矩阵求逆)进行了许多此类运算,每次 运行 都会得到不同的结果,有时是正确的,有时是错误的。看来我的程序对这些操作的准确性非常敏感。 Python 中复数的精度是如何量化的?我能达到的最大值是多少?
我正在使用 Python 2.7.14 和 Numpy 1.14.3。
完整的答案需要很多 space。对于初学者,您需要阅读一本关于数值分析的书,该书解释了二进制浮点类型的工作和存储方式。但这里有一些部分的解释。
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
的数字在 radix point 之后的二进制数字将比 9.0
这样的数字多。这是因为9
使用了4位二进制数,而1
只使用了1位,所以小数点后可以再使用3位二进制数。那么让我们看看你的数字的虚部,1.9021130325903035
:
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
我们看到,虽然数字显示 17 位十进制数字,但当我们将最后一位数字从 5 更改为 6 时,Python 没有看到任何变化。但是,如果我们将该数字向上或向下舍入为 16 位十进制数字,则会发生变化。所以我们可以说该数字存储为 16 位十进制数字甚至更多。这就是为什么当我解释精度时,我说浮点数保证有 15 位有效小数位,但它可能有 16 位,而实际精度略高于此。更简单地说,有 15 或 16 位有效的小数位。
Python 有两种打印浮点数的基本方法:str
函数和 repr
函数。 str
函数打印内容很简单,因此用户无需深入了解细节即可理解结果。 repr
函数给出了更多的细节,并试图打印如此多的细节,以至于存储的数据可以完全由打印的内容决定。请注意,repr
在某些情况下是不可见的,例如在控制台中键入数值,或者如您所见,在 Spyder 中使用变量资源管理器。
当 Spyder 或 Python 对您的号码 1.9021130325903035
执行 repr
时,它会提供足够的数字来完整定义号码。正如我们在上面看到的,如果它只显示 16 位十进制数字,去掉最后的 5
,结果将与存储的略有不同。因此 Python 打印了一个额外的数字,这样你就可以知道这个值是多少。如果 Python 打印了最后的 6
而不是 5
,则值将是相同的,但如果 Python 完全省略了该数字,则该值将被更改。所以 Python 通过 repr
错误的是给了太多数字。尽管打印了 17 个数字,但其中只有 16 个数字是确定的。
最后,由于 np.savetxt
命令中的 %.20e
说明符,您的 csv 文件显示了 20 个十进制数字,因为您告诉 Python 显示 20 个十进制数字。这 20 位小数并不都是“有用的 小数位”,不管你写了什么。只有前 16 或 17 个在虚数部分有用,具体取决于您如何定义 "useful." Python 基本上是将二进制位全零添加到存储值,并将其打印为 20 位十进制数字。但是那些零二进制位没有存储在值中。