1

我的问题:

尝试找出以下 C++ 片段的结果:

#include <iostream>

int main(int argc, char* argv[])
{
    double a = 5.1;
    int b = a * 100;
    std::cout << b << std::endl;

    double c = 6.1;
    int d = c * 100;
    std::cout << d << std::endl;
}

在 Windows 上,我用 VS2008 SP1 编译并运行了上面的代码,得到:

509
610

在 Linux 上,我使用 g++ 编译并运行相同的代码并获得:

509
609

代码有什么问题?

抱歉,我试图为这个问题找到一个标题,因此我可以四处搜索。不过这个问题我也说不上来,就直接在这里介绍了。

任何建议表示赞赏。

4

4 回答 4

5

double不是一个确切的类型,你可以通过应用std::numeric_limitstypetrait看到:

#include <limits>

static_assert(std::numeric_limits<double>::is_exact == false);

因此,涉及双打的计算只是近似的,你观察到的并没有错。

您的代码没有问题。

于 2012-09-10T14:24:30.430 回答
2

通常,双精度(和浮点)是二进制的,您只能精确表示 2 的幂的分数。因此,如果小数部分仅由 1/2、1/4、1/8 等术语组成, 1/16 等浮点数或双精度数将是精确的(当然,除非您遇到精度问题)。

现在,“0.1”是 1/10,实际上是 1/2 * 1/5。5 不是 2 的幂,因此“0.1”不能用二进制表示,只能近似。

于 2012-09-10T14:29:34.910 回答
1

doubleint除非另有说明,否则转换是通过截断来完成的。在您的情况下,由于在四舍五入时会丢失精度(以及 MSalters 指出的少量厄运,因为这只发生在某些“边缘”值附近)。

以下是编译器/操作系统之间行为差异的几个可能原因:

  • 优化:一些编译器以无限精度实现编译时浮动操作。由于您的代码很简单,因此编译器可以在编译时以无限精度进行计算。(您检查过生成的 ASM 代码吗?)
  • 使用不同的内部表示。由于您正在运行 Windows,因此您使用的是 x86 或 x86-64 CPU,这些 CPU 实现了超过 64 位的浮点数,请参阅此处了解一些详细信息。
  • 完全使用不同的架构(您的操作系统都是 64 位吗?)
于 2012-09-10T14:55:29.483 回答
1

正如Kernighan 和 Plauger的编程风格元素的规则之一所述。

10.0时代0.1几乎没有1.0

这意味着浮点数的行为不像数学实数。有一个标准(IEEE 754)如何实现浮点数,但它不是 C 标准的一部分,而仅在 C# 中。

于 2012-09-10T15:25:50.917 回答