由"相同"类型转换的不同结果困惑,浮动到int

don*_*edo 8 c++ gcc type-conversion

如果我首先将浮点计算的值赋给变量,然后使用隐式类型转换将其赋值给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;
}
Run Code Online (Sandbox Code Playgroud)

有没有人能够洞察为什么"正确"是正确的,而"错误"是错误的?

顺便说一句,我在Ubuntu 14.04 LTS上使用gcc 4.8.2,如果重要的话.

Que*_*tin 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;
}
Run Code Online (Sandbox Code Playgroud)

输出:

     right = 65503
also right = 65503
Run Code Online (Sandbox Code Playgroud)


chu*_*ica 6

接受答案后

这不是double对抗float问题。它是一个二进制浮点数和转换int/unsigned问题。

典型的float使用binary32表示没有给出像 6550.3 这样的值的精确表示。

float payloadInTons = 6550.3;
// payloadInTons has the exact value of `6550.2998046875`.
Run Code Online (Sandbox Code Playgroud)

乘以10.0下面的 ,确保计算至少double以精确度完成,精确结果为65502.998046875。然后将产品转换回float. 该double值不能完全表示为float,因此四舍五入到float具有精确值的最佳值65503.0。然后根据需要进行tempVal转换right,值为65503

float tempVal = payloadInTons * 10.0;
unsigned int right = tempVal;
Run Code Online (Sandbox Code Playgroud)

10.0下面乘以,确保计算至少double以精确度完成,结果65502.998046875与以前一样。这一次,该值被直接转换unsigned rawPayloadN为不想要的值为65502。这是因为值被截断而不是四舍五入。

unsigned int rawPayloadN = payloadInTons * 10.0;
Run Code Online (Sandbox Code Playgroud)

第一个“工作”,因为转换的是doublefloatunsigned。这涉及 2 次转换,通常是不好的。在这种情况下,2 个错误变成了一个正确。


解决方案

如果代码尝试过float payloadInTons = 6550.29931640625;(下一个最小的float数字),两个结果都会是65502.

将浮点值转换为某种整数类型的“正确”方法通常是对结果进行四舍五入,然后执行类型转换。

float tempVal = payloadInTons * 10.0;
unsigned int right = roundf(tempVal);
Run Code Online (Sandbox Code Playgroud)

注意:整个问题由于 FLT_EVAL_METHOD. 如果用户的值不为零,浮点计算可能会以比预期更高的精度发生。

printf("FLT_EVAL_METHOD %d\n", (int) FLT_EVAL_METHOD);
Run Code Online (Sandbox Code Playgroud)