关于C语言中double和int之间转换的奇怪结果

 2021-04-27 

A curious result about conversion between double and int in C++

我的问题:

尝试找出以下C代码段的结果:

1
2
3
4
5
6
7
8
9
10
11
12
#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编译并运行了上面的代码,并获得:

1
2
509
610

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

1
2
509
609

代码有什么问题?

对不起,我试图为这个问题找到一个标题,所以我可以四处搜寻。但是,我无法命名此问题,因此我在此直接提出。

任何建议都值得赞赏。


double不是精确类型,如通过应用std::numeric_limits typetrait可以看到的那样:

1
2
3
#include <limits>

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

因此,涉及双打的计算仅是近似值,您观察到的内容没有错。

您的代码没有问题。


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

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


作为Kernighan和Plauger所说的"编程样式元素"的规则之一。

10.0 times 0.1 is hardly ever 1.0

浮动的含义不像数学实数。有一个标准(IEEE 754)如何实现浮点数,但它不是C标准的一部分,而仅在C#中实现。


除非另有说明,否则

doubleint的转换是通过截断完成的。在您的情况下,由于四舍五入时精度的损失(以及MSalters指出的一小笔不幸,因为这仅发生在某些" edge "值附近)。

以下是导致编译器/操作系统之间行为不同的几种可能原因:

  • 优化:某些编译器以无限的精度实现编译时浮动操作。由于您的代码很简单,因此编译器可以在编译时以无限的精度进行计算。 (您是否检查了生成的ASM代码?)
  • 使用不同的内部表示形式。由于您正在运行Windows,因此您使用的x86或x86-64 CPU实现了64位以上的浮点数,有关详细信息,请参见此内容。
  • 完全使用其他体系结构(您的OS都是64位的吗?)