立即警告你,这是一项艰巨的任务。
有一个测试。测试是将大问题解析为我们在工作中遇到的错误的结果。构造__ attribute__((noinline))
禁止编译器执行替换功能(用于优化未破坏的内容)。这是优化保证不会杀死有趣情况的最简单方法。
#include <stdio.h>
double d = 5436277361664796672.000000;
long long ll = 5436277361664796253LL;
int __attribute__((noinline))
func1 (void)
{
double d1 = (double)ll;
if (d > d1)
return 1;
else
return 0;
}
int __attribute__((noinline))
func2 (void)
{
if (d > (double)ll)
return 1;
else
return 0;
}
int
main (void)
{
printf ("%d %d\n", func1(), func2());
return 0;
}
我在intel
和sparc
上运行了此测试。 Gcc
在具有优化且没有优化的模式下使用。获得以下结果:
sparc: "gcc" printed "0 0"
sparc: "gcc -O2" printed "0 0"
intel: "gcc" printed "0 1"
intel: "gcc -O2" printed "1 1"
原因差异是什么?无论如何,在分析情况下,能够自己重复一遍是有用的,但是,当然,几乎没有人可以在sparc
上运行此代码。相反,sparc
可以尝试使用microsoft or borland C compiler
在Windows下运行。我不知道他们将得到什么结果,但无论如何有些东西与任何东西都不匹配(因为我们看到三个不同的结果)
修改1 _ 属性 _((noinline)) - 编译器gcc的扩展(忘了写一下)。因此VisualStudio无法编译它。
答案 0 :(得分:1)
我注意到双常数的声明有19个有效数字,比IEEE双重表示更精确(允许15到17个有效数字)。所以d不能完全保持5436277361664796672.000000。
两个常量定义字符串在第16位处变得不同,因此您处于双精度中的不准确度与这两个数字之间的差异大小相同的区域。因此,不能依赖比较。
我不知道C ++标准是否规定了在将过度精确的字符串转换为double时会发生什么,但如果确切的结果是未定义或依赖于实现,我也不会感到惊讶。
答案 1 :(得分:0)
sparc
版本。因为转换int64-> float64
的标准必须是精度损失。在转换代码时(对于intel)int64-> float80
发生丢失。即基于英特尔的代码具有更高的准确性,但它与标准相矛盾。
也许这是英特尔平台的某种协议,默认情况下允许以这种方式工作。当然,有一些选项可以严格按照标准运行代码(但变慢)