对 "same" 类型转换的不同结果感到困惑,float to int
Puzzled by different result from "same" type cast, float to 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;
}
有谁知道为什么 "right" 是对的,而 "wrong" 是错的?
顺便说一句,如果重要的话,我在 Ubuntu 14.04 LTS 上使用 gcc 4.8.2。
您正在使用 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
接受答案后
这不是 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 次转换,通常 不好 [=71=]。在这种情况下,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);
如果我先将一个值分配给一个变量的浮点计算,然后将其分配给一个带有隐式类型转换的无符号整数,我得到一个答案。但是,如果我将相同的计算直接分配给 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;
}
有谁知道为什么 "right" 是对的,而 "wrong" 是错的?
顺便说一句,如果重要的话,我在 Ubuntu 14.04 LTS 上使用 gcc 4.8.2。
您正在使用 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
接受答案后
这不是 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 次转换,通常 不好 [=71=]。在这种情况下,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);