如果我首先将浮点计算的值赋给变量,然后将其赋值给带有隐式类型转换的unsigned int,我得到一个答案。但是如果我将相同的计算直接分配给unsigned int,再次使用隐式类型转换,我会得到一个不同的答案。
下面是我编译并运行以演示的示例代码:
#include <iostream>
int
main( int argc, char** argv )
{
float payloadInTons = 6550.3;
// Above, payloadInTons is given a value.
// Below, two different ways are used to type cast that same value,
// but the results do not match.
float tempVal = payloadInTons * 10.0;
unsigned int right = tempVal;
std::cout << " right = " << right << std::endl;
unsigned int rawPayloadN = payloadInTons * 10.0;
std::cout << " wrong = " << rawPayloadN << std::endl;
return 0;
}
有没有人能够洞察为什么“正确”是正确的,而“错误”是错误的?
顺便说一下,如果重要的话,我在Ubuntu 14.04 LTS上使用gcc 4.8.2。
答案 0 :(得分:7)
您正在使用double
文字。使用正确的float
文字,一切都很好。
int
main( int argc, char** argv )
{
float payloadInTons = 6550.3f;
float tempVal = payloadInTons * 10.0f;
unsigned int right = tempVal;
std::cout << " right = " << right << std::endl;
unsigned int rawPayloadN = payloadInTons * 10.0f;
std::cout << "also right = " << rawPayloadN << std::endl;
return 0;
}
输出:
right = 65503
also right = 65503
答案 1 :(得分:4)
接受回答后
这不是double
与float
问题。它是一个二进制浮点数并转换为int/unsigned
问题。
典型的float
使用binary32表示法并未提供6550.3等值的精确表示。
float payloadInTons = 6550.3;
// payloadInTons has the exact value of `6550.2998046875`.
乘以下面的10.0
,确保计算至少以double
精度完成,精确结果为65502.998046875
。然后将产品转换回float
。 double
中的float
值无法准确表示,因此会四舍五入为最佳float
,其精确值为65503.0
。然后tempVal
根据需要转换right
,其值为65503
。
float tempVal = payloadInTons * 10.0;
unsigned int right = tempVal;
乘以下面的10.0
,确保计算至少以double
精度完成,精确结果为65502.998046875
,与以前一样。这一次,该值直接转换为unsigned rawPayloadN
,其中包含值为65502
的非期望值。这是因为截断值而非舍入值。
unsigned int rawPayloadN = payloadInTons * 10.0;
第一个“有效”因为转化为double
到float
到unsigned
。这涉及2次转换,通常是坏。在这种情况下,2个错误是正确的。
<强>解决方案强>
如果代码尝试float payloadInTons = 6550.29931640625;
(下一个最小float
个数字),则结果都是65502
。
将浮点值转换为某种整数类型的“正确”方法通常是舍入结果,然后执行类型转换。
float tempVal = payloadInTons * 10.0;
unsigned int right = roundf(tempVal);
注意:整个问题因FLT_EVAL_METHOD
的值而变得复杂。如果用户的值不为零,则浮点计算可能会以高于预期的精度发生。
printf("FLT_EVAL_METHOD %d\n", (int) FLT_EVAL_METHOD);