在同一台机器上运行时,C 程序的浮点精度在过去两周内发生了变化

Floating point [in]accuracy of C program, when running on the same machine, changed over last two weeks

提问人:Bri Bri 提问时间:9/16/2018 最后编辑:Hadi BraisBri Bri 更新时间:9/16/2018 访问量:167

问:

以下 C 代码今天在两个使用 Microsoft 编译器(随 Visual Studio 2017 社区一起安装)的系统上编译,这两个系统都具有现代 64 位 Intel 处理器并运行 Windows 10:

#include <math.h>
#include <stdio.h>

int main() {
    int a = 64, b = 2;
    double logA = log(a);
    double logB = log(b);
    double c = logA / logB;
    printf("logA: %0.20lf\n", logA);
    printf("logB: %0.20lf\n", logB);
    printf("c: %0.20lf\n", c);
    printf("result: %d\n", ((int)c));
    return 0;
}

我们称它们为“系统 A”和“系统 B”,以保持清晰。两个系统打印的 和 的值完全相同:logAlogB

logA: 4.15888308335967149532
logB: 0.69314718055994528623

但是,对于和系统 A 打印:cresult

c: 6.00000000000000000000
result: 6

...系统 B 打印:

c: 5.999999999999...
result: 5

(我不再有它产生的确切结果,但足以说它比 6.0 略小。

我尝试在其他几个系统上编译相同的代码,包括运行 Windows 7 和 VS Community 2013 的旧系统以及运行 macOS 10.12 和 Xcode 9.3.1 的 mac,它们的结果与系统 A 一致,而不是系统 B。

这是它变得非常奇怪的地方:

更令人困惑的是,两周前在系统 B 上编译程序时,它产生了与系统 A 相同的结果!在此期间发生了一些变化,导致编译的程序产生不同的答案。

我的问题是:这到底是怎么发生的?!

我知道浮点不准确,并没有试图证明或原谅将结果除以和不四舍五入或以其他方式解释不准确的错误。这显然是一个错误。log(a)log(b)

但是这个特殊的错误只在最近两周才显现出来,而且只在一个系统上。我无法在其他任何地方重现它。

据我所知,双精度浮点数学的结果是基于 CPU,而不是操作系统、编译器、C 运行时或任何其他软件

为什么两周前生成 6.00000000000 的系统会突然切换到生成 5.9999999999?

(当然,Windows 10 喜欢自动静默更新自己,但系统 B 的所有者没有手动安装任何可以轻松解释此更改的更新。

为了我自己的教育和内心的平静,我真的很想知道这个问题的答案。

C x86 Intel 浮点精度

评论

0赞 Daniel Pryden 9/16/2018
系统是否始终如一地产生不同的结果,还是只发生过一次?我最好的猜测是,在上下文切换期间,80 位 FPU 寄存器会刷新到 64 位,但这实际上只是黑暗中的一枪。
0赞 Bri Bri 9/16/2018
系统 B 始终产生与系统 A 不同的结果。这不是一次性的事情。
1赞 Eric Postpischil 9/16/2018
问题中的假设是“双精度浮点数学的结果基于 CPU,而不是操作系统、编译器、C 运行时或任何其他软件”是不正确的。英特尔处理器提供了一些浮点辅助功能,但这些功能是有限的,标准库数学例程是在编译器和/或操作系统随附的软件中实现的。Microsoft的例行公事过去因一些不准确而臭名昭著。
2赞 Hadi Brais 9/16/2018
似乎 使用 ,编译器只调用一次,并用于计算第二个的近似值。另一方面,or 发出对 和 use 的调用来计算。/fp:fastlogmulsdlog/fp:strict/fp:preciselogdivsdc
2赞 phuclv 9/16/2018
log 和其他超越函数不需要正确舍入。要计算一个数字的长度,有更好的方法:_BitScanForward64转换为单个指令,而不是数百或数千个来计算对数。另请参阅计数位或查找最右边|最左边的位graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious

答: 暂无答案