这段代码让我抓狂了:

#include <stdio.h>

    int main()
{
double x;
const double d=0.1;
x=d ;
for (int i=0; i<30; i++)
    {
    printf("Cycle %d  Value :%.20e \n",i,x);
    x=x*(double)11.-(double)10*d; //11*0.1 = 1.1 - 10*0.1 = 1 => 0.1

    }
return 0;
}

事实上,我试图证明一个病理病例是由于内部表现
IEEE754标准中的浮点数。
在MacOS或Windows计算机上,最终输出行将显示:
周期29值:1.2808415315612750000 E+13
但是在linux(scientific linux 5.4)上,代码运行不会有问题。
通过阅读我发现:
在freebsd、netbsd和openbsd等bsd系统上,硬件双精度舍入模式是默认的,与本机双精度平台具有最大的兼容性。在x86 gnu/linux系统上,默认模式是扩展精度(目的是提供更高的精度)。
在同一页上,还解释了如何在Linux系统上启用双精度舍入,而不是如何在其他系统上使用扩展精度。
这在macos或windows上可能吗?如何?

最佳答案

在OS X上简单地使用扩展精度很容易:

x=11.L*x - 10.L*d;

后缀L导致两个文本long doubles而不是doubles,这将强制按照c的表达式求值规则对整个表达式进行80位扩展。
除此之外,你的问题似乎有些混乱;你说“……在Linux上,代码运行不会有问题。
os x结果和linux结果都符合ieee-754和c标准。他们两个都没有“问题”。
OSX结果在不支持(非标准)80位浮点类型的硬件上是可复制的。Linux的结果不是。
依赖于中间结果保持在80位扩展的计算是脆弱的;更改编译器选项、优化设置甚至程序流都可能导致结果更改。OSX的结果在这些变化中是稳定的。
最后,你必须记住浮点运算不是真正的运算。Linux上获得的结果更接近用实数计算表达式时获得的结果,这一事实并不能使该方法更好(或更糟)。
对于每一个自动使用扩展精度保存了一个天真的浮点用户的情况,我可以向您展示一个这样的情况:评估模式的不可预测性引入了一个微妙而难以诊断的错误。这些通常被称为“过度精确”错误;最近最著名的例子之一是一个允许用户将2.2250738585072011e-308放入web表单并使服务器崩溃的错误。最终的原因正是编译器在程序员的背后,保持了比指令更高的精度。OS X不受此错误影响,因为双精度表达式是以双精度计算的,而不是扩展的。
只要系统是可复制和可移植的,人们就可以接受浮点运算的知识。以双精度计算双精度表达式和以单精度计算单精度表达式提供了这些属性。使用扩展的精度评估会破坏它们。在工具不可预测的环境中,您不能进行严肃的工程设计。

10-08 11:57
查看更多