一个常见的假设是1 / x * x == 1
. 在常见的符合 IEEE 754 的硬件上打破这一点的最小正整数是多少?
当乘法逆的假设失败时,写得不好的有理算术就不再起作用了。因为包括 C 和 C++ 在内的许多语言默认使用四舍五入将浮点数转换为整数,所以即使是一个小错误也可能导致整数结果偏移 1。
快速测试程序会产生各种结果。
#include <iostream>
int main () {
{
double n;
for ( n = 2; 1 / n * n == 1; ++ n ) ;
std::cout << n << " (" << 1 - 1/n*n << ")\n";
for ( ; (int) ( 1 / n * n ) == 1; ++ n ) ;
std::cout << n << " (" << 1 - 1/n*n << ")\n";
}
{
float n;
for ( n = 2; 1 / n * n == 1; ++ n ) ;
std::cout << n << " (" << 1 - 1/n*n << ")\n";
for ( ; (int) ( 1 / n * n ) == 1; ++ n ) ;
std::cout << n << " (" << 1 - 1/n*n << ")\n";
}
}
在使用 GCC 4.3.4 的ideone.com上,结果是
41 (5.42101e-20)
45 (5.42101e-20)
41 (5.42101e-20)
45 (5.42101e-20)
使用 GCC 4.5.1 会产生相同的结果,但据报道误差范围恰好为零。
在我的机器上(GCC 4.7.2 或 Clang 4.1),结果是
49 (1.11022e-16)
49 (1.11022e-16)
41 (5.96046e-08)
41 (5.96046e-08)
这与--fast-math
选项无关。使用-mfpmath=387
令人惊讶的产生
41 (5.42101e-20)
41 (5.42101e-20)
41 (5.42101e-20)
41 (5.42101e-20)
值 5×10 -20似乎暗示对应于 64 位尾数的 epsilon,即使用 Intel 80 位扩展精度的内部计算。
这似乎高度依赖于 FPU 硬件。是否有适合测试的可靠值?
注意:我不在乎语言标准或编译器对浮点数系统的保证,尽管我认为在任何常见的编程系统中都没有很多有意义的保证。我想知道数字和现实世界计算机之间的交互。