浮点数和双精度浮点数精度有限导致的错误

3
在C++中,我使用以下代码来计算由于float和double的有限精度而导致误差的数量级:
 float n=1;
 float dec  = 1;

 while(n!=(n-dec)) {
    dec = dec/10;
 }
 cout << dec << endl;

在双精度情况下,我只需要在第1和第2行中将float替换为double。

现在当我在Unix系统上使用g++进行编译和运行时,结果如下:

Float  10^-8
Double 10^-17

然而,当我使用MinGW在Windows 7上编译和运行它时,结果是这样的。
Float  10^-20
Double 10^-20

这是什么原因?


1
有些迹象表明,MinGW 将 n!=(n-dec) 的中间结果存储在 80 位扩展精度中。10^-20 左右是 80 位浮点数的 epsilon。 - Mysticial
3个回答

2
我想把我的评论变成答案并加以扩展。这是我的假设,我可能是错误的。
在Windows上使用MinGW可能会尝试通过将表达式的中间结果提升为x86的完整80位精度来保留精度。
因此,表达式“n!=(n-dec)”的两侧都被评估为64位精度(80位FP具有64位尾数)。
2^-64 ~ 10^-20

因此,这些数字是有意义的。

Visual Studio(默认情况下)也会提升中间值。但仅限于双精度。


GCC中使用的优化标志很可能也会改变输出结果,因为它会改变处理浮点数的方式。还要注意的是,这不仅仅涉及到编译器,还包括芯片本身以及它所使用的浮点模式。编译器可能还会为浮点数生成特殊的截断命令。有许多变量,但是你的答案基本上是正确的。 - edA-qa mort-ora-y
@edA-qa mort-ora-y:同意。我再想了一下。只需要将FP模式设置为扩展精度即可。代码也足够小,不会溢出x87寄存器。因此,在存储时进行舍入是不会发生的。 - Mysticial

0
为什么不在两个操作系统中检查float和double的大小呢?

在W7上,float是32位,double是64位(使用sizeof())。我如何将其与我上面的发现联系起来? - Ben

0

这表明不同的环境使用不同大小的float和double。

根据C++规范,double的大小至少应与float相同。如果要了解系统上类型的确切大小,请使用sizeof

您的测试似乎表明g++在float和double上使用不同的大小(分别为32位和64位),而您的Windows系统上的MinGW32使用相同的大小。两个版本都符合标准,通常不能依赖任何一种行为。


请看我在suresh的帖子下面的评论。在我的Windows系统上,float和double使用的大小是不同的。 - Ben
@Agentlien:在这两个系统上,float占用4个字节,double占用8个字节。当关闭优化时,MinGW的行为与Unix系统一样。 - TonyK

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接