Python算术用小数字

use*_*890 7 python numerical

当我在Python中使用小数字进行算术运算时,我得到以下意外结果:

>>> sys.float_info
sys.float_info(max=1.7976931348623157e+308, max_exp=1024, max_10_exp=308, min=2.2250738585072014e-308, min_exp=-1021, min_10_exp=-307, dig=15, mant_dig=53, epsilon=2.220446049250313e-16, radix=2, rounds=1)
>>> (1. - (1.e-17) ) < 1.
False
Run Code Online (Sandbox Code Playgroud)

我知道浮点数不具有无限精度,但它应该能够处理像"1e-17"这样的"大"小数,不应该吗?

wim*_*wim 8

>>> import numpy as np
>>> np.nextafter(1., 0.)
0.99999999999999989
Run Code Online (Sandbox Code Playgroud)

这是继1.方向之后的下一个浮动0.

我想它比它1. - 1.e-17更接近,所以当评估时它会让你完全回来.使用更远的其他漂浮物是没有意义的. 1.numpy.nextafter(1., 0.)1. - 1.e-17

相关问题 - > 以尽可能小的量增加python浮点值


小智 6

首先,让我们回顾一下epsilon真的是在返回值sys.float_info

Epsilon(或)是满足 0.5 + ? 0.5 和 0.5 - ? 0.5

Python 告诉您将导致0.5重复递增或递减的最小数字是epsilon=2.220446049250313e-16-但这仅适用于值 0.5。您正在尝试增加1.01.0e-17。这是一个更大的值(1.0 对 0.5),增加的数字比 0.5(1.0e-17 对 2.2e-16)更小。您大致偏离了一个数量级,因为 1.0e-17 的增量值比 1.0 的相对 epsilon 小一个数量级。

你可以在这里看到这个:

这些改变了价值 0.5

>>> 0.5+sys.float_info.epsilon
0.5000000000000002
>>> 0.5-sys.float_info.epsilon
0.4999999999999998
Run Code Online (Sandbox Code Playgroud)

这些值不会:

>>> 0.5+sys.float_info.epsilon/10.0
0.5
>>> 0.5-sys.float_info.epsilon/10.0
0.5
>>> 5.0+sys.float_info.epsilon
5.0
>>> 5.0-sys.float_info.epsilon
5.0
Run Code Online (Sandbox Code Playgroud)

解释:

IEEE 754定义了当今大多数标准计算机上使用的浮点格式(专业计算机或图书馆可能使用不同的格式。)IEEE 754的64 位格式使用 53 位精度来计算和 52 位存储到浮点数的尾数点值。由于您有一个固定的 52/53 位可以使用,尾数的大小和精度会随着值的增大/减小而变化。那么随着浮点数的相对大小的变化而变化。0.5 的值与 1.0 和 100.0 的值不同。

出于各种非常好的和特定于平台的原因(存储和表示、舍入等),即使您可以使用较小的数字,epsilon 也被定义为对 64 位浮点格式使用 52 位精度。由于大多数 Python 实现使用 C 双浮点数作为浮点数,因此可以证明:

>>> 2**-52==sys.float_info.epsilon
True
Run Code Online (Sandbox Code Playgroud)

查看您的平台将执行多少位:

>>> 0.5 + 2.0**-53
0.5000000000000001
>>> 0.5 - 2.0**-53
0.4999999999999999
>>> 0.5 + 2.0**-54
0.5                           # fail for 0.5 + 54 bits...
>>> 0.5 - 2.0**-54
0.49999999999999994           # OK for minus
>>> 0.5 - 2.0**-55
0.5                           # fail  for 0.5 minus 55 bits...
Run Code Online (Sandbox Code Playgroud)

您的问题有几种解决方法:

  1. 您可以使用nextafter的 C99 概念来计算适当的 epsilon 值。对于 Python,使用 numpy 或 Decimal 类来计算nextafter. 更多关于nextafter我以前的回答在这里
  2. 使用整数。一个 64 位整数将清楚地处理第 17 个数量级的 epsilon 值而无需四舍五入。
  3. 使用任意精度的数学库。十进制在标准 Python 发行版中。

重要的概念是,的值是相对于值的(如果你是递增或递减)。

这可以在这里看到:

>>> numpy.nextafter(0.0,1.0)-0.0
4.9406564584124654e-324                 # a relative epsilon value of 4.94e-324
>>> numpy.nextafter(0.01,1.0)-0.01
1.7347234759768071e-18                  # 1e-17 would still work...
>>> numpy.nextafter(0.1,1.0)-0.1
1.3877787807814457e-17                  # 1e-17 would >>barely<< work...
>>> numpy.nextafter(0.5,1.0)-0.5
1.1102230246251565e-16                  # a relative epsilon value of 1.1e-16
>>> numpy.nextafter(500.0,501.0)-500.0
5.6843418860808015e-14                  # relative epsilon of 5.6e-14
>>> numpy.nextafter(1e17,1e18)-1e17
16.0                                    # the other end of the spectrum...
Run Code Online (Sandbox Code Playgroud)

所以你可以看到 1e-17 可以轻松地增加 0.0 和 0.1 之间的值,但不会有太多大于这个的值。如上所示,1e17 的相对值是 16。


NPE*_*NPE 3

它应该能够处理像 1e-17 这样的“大”小数字,不是吗?

不一定(这取决于数字)。Afloat不能准确代表1e-171-(1e-17)。对于后者,它可以表示的最接近的数字是1

我建议您阅读《每个计算机科学家应该了解的浮点运算》