2

在执行 unit64 变量与浮点数的乘法时,我观察到 mingw 的奇怪行为。这是编译器的问题吗?

下面是我的代码:

#include <iostream>
using namespace std;

int main() {

    uint64_t myvar = 4293057;
    float mycrasher = 1000;
    myvar = myvar*mycrasher;
    cout << "value after mul is "<<myvar << endl; 
    return 0;
}

显示的输出值是 4293057024 而不是 4293057000!!

4

1 回答 1

1

IEEE754 单精度值(例如您的float)只有大约七位十进制精度。除此之外,它是不精确的。您甚至不必将其乘以 1000,将其乘以 10 即可得到42930568.

您可以看到以下代码发生了什么:

#include <iostream>
int main () {
    float xyzzy = 42930570;
    std::cout.precision (5);
    std::cout << "xyzzy is " << std::fixed <<xyzzy << '\n';
    return 0;
}

输出不那么精确的:

42930568.00000

为了更全面地解释,IEEE754 浮点值的精度受到限制,仅仅是因为它们具有有限数量的可用于该目的的位。单精度值的长度为 32 位,其中 23 位用于小数(其他位用于符号和指数)。这 23 位相当于大约 7 个十进制数字。你可以在这里找到进一步的分析。

数字 42930570 无法以单个精度值精确表示。您要么得到 is 的位模式0x4c23c462,要么得到42930568下一个更高0x4c23c46342930572.


他们被转换为float而不是的uint64_t原因是因为这就是标准所说的。在 C++03 中,“乘法运算符”部分 (5.6) 说:

通常的算术转换是在操作数上执行的,并确定结果的类型。

通常的算术转换在第 5 节第 9 段中有详细说明,包括:

  • 如果任一操作数是 long double 类型,则另一个应转换为 long double。
  • 否则,如果任一操作数为双精度,则另一个应转换为双精度。
  • 否则,如果任一操作数为浮点数,则另一个应转换为浮点数。
  • 更多处理整数类型的东西(实际上并没有这么说,我在解释)。

由于您有 afloat和 a uint64_t,因此上面的第三个要点涵盖了这一点。在“浮点-积分转换”部分(4.9)中,我们看到:

整数类型或枚举类型的右值可以转换为浮点类型的右值。如果可能,结果是准确的。否则,它是下一个较低或较高可表示值的实现定义选择。

因此,这就是为什么您会看到精度下降的原因。

这在 C++11 中没有改变。措辞发生了变化,并且更加冗长,但这些部分仍然归结为相同的结果。

于 2012-12-03T01:00:43.987 回答