实数不是实数

实数不是实数

说实数不是实数,这不仅仅是在玩文字游戏,而是一种计算现实。让我们做一个简单的实验:在您最喜欢的数字处理工具中尝试以下操作。在Excel中:

=如果(1 + 1 e - 016 = 1, 1, 0)
将打印1。在Python中:
>>> 1 == 1+1e-16 True
在C语言中,代码
#include int main(void) {if (1+1e-16 == 1) printf("True\n");其他printf(“错误\ n”);返回0;}
将打印真正的.R:
> 1 == 1+1e-16 [1] TRUE

注意,这种行为并不局限于数字;它也会发生在更大的数字上。例如:

>>> 1+1e16 == 1e16 True
这表明精度其结果取决于所涉及数字的相对规模。

虽然这种行为很典型,但也有一些例外。一个是gnu bc命令行工具:

公元前> 1.0 = = 1.0 + 10 ^(-16)1规模20 = = 1.0 + 1.0 = 10 ^ (-16)0 1.0 = = 1.0 + 10 ^ (-21)1
当我们设置规模参数< span > < / span > 20美元美元< span > < / span >,代码能够识别不同的数字。这只是改变了标准;公元前还是认不出最后两个数字的区别。另一个库允许扩展,甚至无限的(到内存)精度是GNU多精度算术库,但其细节超出了本文的范围。

原因是失败计算机必须以位序列的形式存储数字,而大多数常见的实现都遵循IEEE 754标准。特别是IEEE-754为双精度格式。这个标准是如此的普遍以至于几乎所有的计算机都有专门的硬件来提高数字运算的性能。一个结果是,对替代扩展数表示的数学运算往往比对按照IEEE 754标准表示的数进行运算要慢得多。10倍甚至100倍的退化是常见的。

由于硬件支持双精度算法所获得的性能,Gurobi依赖于这个标准(大多数软件也是如此)。然而,这样的速度是有代价的:计算结果往往与数学所规定的不同。例如,关联属性(A + (b + c) = (A + b) + c)是算术的一个基本属性,但双精度算术给出(在Python中):

>>> (1+1e-16)+1e-16 == 1+ (1e-16 +1e-16) False
此外,许多普通数字(如0.1)不能精确表示。

因此,简单的问题,如两个数是否相等,或一个数是否等于零,或一个数是否整数,在使用浮点运算时可能会相当复杂。