我在使用float函数执行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 !!
答案 0 :(得分: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位等于大约七位小数。您可以找到进一步的分析here。
数字42930570无法在单个精度值中精确表示。您要么得到0x4c23c462
的位42930568
,要求得0x4c23c463
的下一个42930572
。
他们被转换为float
而不是uint64_t
的原因是因为这就是标准所说的。在C ++ 03中,“乘法运算符”部分(5.6)表示:
通常的算术转换是在操作数上执行的,并确定结果的类型。
通常的算术转换详见第5节第9段,包括:
由于您有float
和uint64_t
,因此上面的第三个要点涵盖了这一点。在“浮动 - 积分转换”部分(4.9)中,我们看到:
整数类型或枚举类型的右值可以转换为浮点类型的右值。如果可能,结果是准确的。否则,它是实现定义的下一个较低或较高可表示值的选择。
因此 为什么你会看到失去精确度。
在C ++ 11中没有改变。措辞有所改变,而且更加冗长,但这些部分仍然归结为相同的结果。