[英]different behaviours for double precision on different compiler
我的代码很简单
double d = 405, g = 9.8, v = 63;
double r = d * g / (v * v);
printf("%s\n",(r>1.0)?"GT":"LE");
这是我的结果
g ++ - mingw,vc ++,c#,haskell都在我的机器上运行,带有i7-2630QM
Python-win32版本来自我的朋友,他也从他的g ++获得LE - mingw-3.4.2。
ubuntu版本来自另一位朋友......
只有g ++给我LE,其他都是GT。
我只是想知道哪一个是错的,g ++或其他。
或者应该是什么,GT或LE,IEEE 754?
IEEE 754 64位二进制结果是GT。
包含9.8的两个完全可表示的值是:
9.7999999999999989341858963598497211933135986328125
9.800000000000000710542735760100185871124267578125
第二个更接近9.8,因此应该在正常的舍入模式中选择它。 它略大于9.8,导致产品略大于实数算术产生的产品,3969.00000000000045474735088646411895751953125。 将v
转换为double是精确的, v*v
乘法也是如此。 结果是将数字略大于3969除以3969.舍入结果为1.0000000000000002220446049250313080847263336181640625
当评估d * g
时可能会出现差异,因为该产品的数学结果必须向上舍入以产生可表示为double
的值,但是long double
结果更准确。
大多数编译器将405
和63
转换9.8
精确double
并将9.8
转换为9.800000000000000710542735760100185871124267578125,尽管C ++标准为它们提供了一些余地。 v * v
的评估通常也是精确的,因为数学结果是完全可表示的。
通常,在英特尔处理器上,编译器可以通过以下两种方式之一来评估d * g
:使用double
算法或使用带有英特尔80位浮点格式的long double
精度。 当使用double
计算时,405•9.800000000000000710542735760100185871124267578125生成3969.00000000000045474735088646411895751953125,并将其除以3969会产生略大于1的数字。
使用long double
评估时,产品为3969.000000000000287769807982840575277805328369140625。 该产品虽然大于3969,但略小,使用long double
算法除以3969会产生1.000000000000000072533125339280246635098592378199100494384765625。 将此值分配给r
,编译器需要将其转换为double
。 (额外的精度也可以仅在中间表达式中使用,而不是在分配或管型。)此值是足够接近一个舍入它double
产生一个。
您可以通过对每个单独的操作使用强制转换或赋值来减轻编译器之间的某些(但不是全部)变化:
double t0 = d * g;
double t1 = v * v;
double r = t0/t1;
回答你的问题:因为表达式应该评估为“相等”,所以测试r>1.0
应该是假的,并且打印的结果应该是"LE"
。
实际上,你遇到的问题是像9.8
这样的数字不能完全表示为浮点数(网上有数百个好的链接来解释为什么会这样)。 如果您需要精确的数学运算,则必须使用整数。 或者bigDecimal
。 或者一些这样的事情。
只有当小数部分可以通过二维分数(如0.5,0.25,......等)求和时,从小数部分到二进制分数的转换才是精确的。
示例中的数字9.8包含分数0.8,它不能使用二进制数系统表示为精确分数。 因此,根据表示小数的精度,不同的编译器会给出不同的结果。
使用数字9.75运行程序,然后所有编译器都会给你相同的结果,因为
0.75 = 0.25 + 0.125 = 2 -2 + 2 -3
因此,可以使用二进制分数精确表示数字9.75。
我测试了代码,这应该返回GT。
int main() {
double d = 405.0f, g = 9.8f, v = 63.0f;
double r = d * g / (v * v);
printf("%s\n",(r>1.0f)?"GT":"LE");
}
GCC编译器将405视为int,因此“double d = 405”实际上是“double d =(double)405”。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.