从float到int的奇怪转换

时间:2013-11-25 18:19:13

标签: c++

for(float i = 40; i <= 42; i+=0.1f)
{
    float offset = (i-40) * 10 * sizeof(float);
    int wtf = offset;
    printf("%.1f =?= %d\n", offset, wtf);
    fseek(fin, offset, SEEK_SET);
    fread(&tf, sizeof(float), 1, fin);
    //printf("%.1f %.4f\n", i, tf);
}

输出:

  

0.0 =?= 0   4.0 =?= 3   8.0 =?= 7   12.0 =?= 11   16.0 =?= 15   20.0 =?= 19   24.0 =?= 23   28.0 =?= 27   32.0 =?= 31   36.0 =?= 35   40.0 =?= 39   44.0 =?= 43   48.0 =?= 47   52.0 =?= 51   56.0 =?= 55   60.0 =?= 59   64.0 =?= 63   68.0 =?= 67   72.0 =?= 71   76.0 =?= 75   80.0 =?= 79

我不明白这一点,你能帮助我吗?

3 个答案:

答案 0 :(得分:3)

问题是0.1不能完全表示为二进制浮点数。每个float值略低于您的预期,转换为int向下舍入,给出的值比您预期的低一个。

您可以通过四舍五入到最接近的整数来获得预期值:

int wtf = std::round(offset);

答案 1 :(得分:1)

i = 40.1f偏移量为3.99993896且不完全为4.对于您的示例,如果使用c ++ 11标准或者圆形不可用,则可以使用std::round(offset) {{ 1}}

浮点数不能代表Universe中的所有值,在某些情况下,纸张上的数学在浮点数上是正确的,可能不是。

答案 2 :(得分:0)

在碱2中表达的

0.1是

0.0001100110011001100110011001100110011...

分数中的0011无限重复,正如3在1/3 = 0.3333333 ...基数10中所做的那样。由于实际的浮点数值只能保持有限的数字,所以必然是近似误差。

可以用基数2中有限位数精确表示的唯一小数是分母为2的整数的有理数。例如,用0.125f(= 1/8)代替0.1f

for(float i = 40; i <= 42; i+=0.125f)
{
    float offset = (i-40) * 10 * sizeof(float);
    int wtf = offset;
    printf("%.1f =?= %d\n", offset, wtf);
}

导致没有截断错误的值:

0.0 =?= 0
5.0 =?= 5
10.0 =?= 10
15.0 =?= 15
20.0 =?= 20
25.0 =?= 25
30.0 =?= 30
35.0 =?= 35
40.0 =?= 40
45.0 =?= 45
50.0 =?= 50
55.0 =?= 55
60.0 =?= 60
65.0 =?= 65
70.0 =?= 70
75.0 =?= 75
80.0 =?= 80

这是因为0.125 base 10恰好等于0.001 base 2。