4

我的代码很简单

double d = 405, g = 9.8, v = 63;
double r = d * g / (v * v);
printf("%s\n",(r>1.0)?"GT":"LE");

这是我的结果

  • g++-mingw32-v4.8.1: LE(结果确实是 EQ)
  • g++ on ubuntu : GT(这个结果来自我的朋友,只是手头没有 linux)
  • VC++ 11:GT
  • C#(.Net 4.5):GT
  • Python v2.7.3:GT(这也来自我的朋友)
  • Haskell(GHCi v7.6.3):GT

g++-mingw、vc++、c#、haskell 都在我的机器上运行,带有 i7-2630QM

Python-win32 版本来自我的朋友,他也从他的 g++-mingw-3.4.2 中获得了一个LE 。

而ubuntu版本来自另一个朋友...

只有g++给了我LE,其他都是GT。

我只想知道哪个是错的,g++ 还是其他的。

或者 IEEE 754 中的 GT 或 LE 应该是什么?

4

5 回答 5

4

IEEE 754 64 位二进制结果为 GT。

包含 9.8 的两个完全可表示的值是:

9.7999999999999989341858963598497211933135986328125
9.800000000000000710542735760100185871124267578125

第二个更接近9.8,所以应该在正常舍入模式下选择。它比 9.8 略大,产生的乘积比实数算术产生的乘积略大,3969.00000000000045474735088646411895751953125。到 double的转换v是精确的,v*v乘法也是如此。结果是将略大于 3969 的数字除以 3969。四舍五入的结果是 1.0000000000000002220446049250313080847263336181640625

于 2013-09-17T04:32:36.833 回答
1

仅当十进制分数可以用二进制分数(如 0.5、0.25、...等)相加时,从十进制分数到二进制分数的转换才是精确的。

您的示例中的数字 9.8 包含分数 0.8,不能使用二进制数系统将其表示为精确分数。因此,不同的编译器会根据表示小数的精度为您提供不同的结果。

使用数字 9.75 运行你的程序,那么所有的编译器都会给你相同的结果,因为

0.75 = 0.25 + 0.125 = 2 -2 + 2 -3

所以数字 9.75 可以用二进制分数精确表示。

于 2013-09-17T03:28:29.090 回答
1

评估时可能会出现差异d * g,因为该乘积的数学结果必须向上四舍五入才能产生可​​在 中表示的值double,但long double结果更准确。

尽管 C++ 标准为它们提供了一些余地,但大多数编译器都将精确转换405并转换为 9.800000000000000710542735760100185871124267578125。的评估通常也是精确的,因为数学结果是精确可表示的。63double9.8v * v

通常,在英特尔处理器上,编译器d * g以两种方式之一进行评估:使用double算术或使用long double英特尔的 80 位浮点格式。当使用double405•9.8000000000000000710542735760100185871124267578125 进行评估时,产生 3969.00000000000045474735088646411895751953125,然后将其除以 3969 得到一个略大于 1 的数字。

用 评估时long double,乘积为 3969.000000000000287769807982840575277805328369140625。该乘积虽然大于 3969,但略小,使用long double算术除以 3969 得到 1.000000000000000072533125339280246635098592378199100494384765625。当这个值被赋值给r时,编译器需要将它转换为double。(额外的精度只能用在中间表达式中,不能用在赋值或强制转换中。)这个值足够接近 1,四舍五入double产生 1。

您可以通过对每个单独的操作使用强制转换或赋值来减轻编译器之间的一些(但不是全部)差异:

double t0 = d * g;
double t1 = v * v;
double r = t0/t1;
于 2013-09-17T14:11:34.520 回答
0

回答您的问题:由于表达式的计算结果应为“等于”,因此测试r>1.0应为假,打印的结果应为"LE".

实际上,您遇到的问题是9.8不能将类似的数字完全表示为浮点数(网络上有数百个很好的链接可以解释为什么会这样)。如果你需要精确的数学,你必须使用整数。或bigDecimal。或者类似的东西。

于 2013-09-17T03:21:22.723 回答
-1

我测试了代码,这应该返回 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”。

于 2013-09-17T07:19:27.967 回答