单精度和双精度铸造给出了不同的答案

Single-Precision and Double-Precision Casting Gives Different Answers

本文关键字:答案 精度 双精度 单精度      更新时间:2023-10-16

所以我有以下代码:

#include <iostream>
int main(){
    float number = 0.6;
    int anotherNumber = 20;
    int value = (int) ((float) anotherNumber * number);
    std::cout << value;
    std::cin.get();
}

它给出了12,就像它应该考虑20 * 0.6 = 12。但是,如果我将所有浮点数改为双精度:

#include <iostream>
int main(){
    double number = 0.6;
    int anotherNumber = 20;
    int value = (int) ((double) anotherNumber * number);
    std::cout << value;
    std::cin.get();
}

结果是11。让事情变得更奇怪的是,如果我改变代码,让值先存储在一个变量中,然后才存储,它又给出了正确的答案(12)。

#include <iostream>
int main(){
    double number = 0.6;
    int anotherNumber = 20;
    double intermediate = (double) anotherNumber * number;
    int value = (int) intermediate;
    std::cout << value;
    std::cin.get();
}

这到底是怎么回事?

0.6不能精确地用任何二进制浮点格式表示。根据数据类型,它有时大一些,有时小一些。请参阅每个程序员都应该知道的关于浮点算术的详细说明。

"存储在内存中"版本是不同的,因为x87 FPU内部使用80位浮点寄存器。

编辑:详细计算:

float 0.6 in memory;
.100110011001100110011010
loaded to register:
.10011001100110011001101000000000000000000000000000000000000000000
multiplied by 20:
1100.0000000000000000000010000000000000000000000000000000000000000
rounded down:
1100
double 0.6 in memory
.10011001100110011001100110011001100110011001100110011
loaded to register:
.10011001100110011001100110011001100110011001100110011000000000000
multiplied by 20:
1011.1111111111111111111111111111111111111111111111111110000000000
rounded down:
1011
double 0.6 in memory
.10011001100110011001100110011001100110011001100110011
loaded to register:
.10011001100110011001100110011001100110011001100110011000000000000
multiplied by 20:
1011.1111111111111111111111111111111111111111111111111110000000000
converted to double-precision and stored to memory:
1100.0000000000000000000000000000000000000000000000000
loaded to register:
1100.0000000000000000000000000000000000000000000000000000000000000
rounded down:
1100