C(C ++,Objective-C)中将浮点数强制转换为整数会导致减小的整数。

3

我写了一个iPhone应用程序,遇到了有关float和int之间的类型转换问题。我已经将代码重写为C语言,并在OS X(控制台和Xcode)、Linux(控制台)或Windows(Visual Studio)下进行编译,结果始终相同:

// Calculation of a page index depending on the amount of pages, its x-offset on the view
// and the total width of the view
#include <stdio.h>

int main()
{
    int   result   = 0;
    int   pagesCnt = 23;
    float offsetX  = 2142.0f;
    float width    = 7038.0f;

    offsetX = offsetX / width;
    offsetX = (float)pagesCnt * offsetX;
    result  = (int)offsetX;

    printf("%f (%d)\n", offsetX, result);
    // The console should show "7.000000 (7)" now
    // But actually I read "7.000000 (6)"

    return 0;
}

当使用计算器进行计算时,我们会失去一些精度。x在计算器中的结果为7.00000000000008而不是7.000000。
然而,就我所了解的C语言而言,这应该不是问题,因为C语言在将浮点数转换为整数时会截断小数点后面的位数。在这种情况下,这实际上是我想要的。
如果使用double而不是float,则结果将如预期一样,但我不需要双精度,并且它不应该有任何区别。
我是否理解错了什么?是否存在应避免使用(int)进行转换的情况?为什么C会减少结果?我是否应该始终使用double?
非常感谢!
编辑:我表述有误:当使用double而不是float时确实会有所不同。我的意思是,对于(int) 7.000000f或7.00000000000008,它不应有任何区别。
第二次编辑:多亏了你,我现在明白了我的错误。在没有定义浮点精度的情况下使用printf()是错误的。将6.99...转换为6是正确的。因此,遇到这种问题时,我将来会使用double。

你可以始终编写 offsetX * pagesCnt / width 来尽可能延迟非整数值。还要注意,在 printf 的可变参数中存在转换为 double 的情况。 - Kerrek SB
3个回答

4

当我增加输出的精度时,从你的程序得到的结果是6.99999952316284179688 (6),因此6看起来是正确的。


谢谢提示。正如我在评论丹尼尔·菲舍尔的回答中所说,我现在理解了。 - snoopysalive

1

编译器在许多情况下不能自由更改浮点运算的顺序,因为有限精度算术通常不是结合的。即

(23 * 2142) / 7038 = 7.00000000000000000000

(2142 / 7038) * 23 = 6.99999999999999999979

这些不是单精度结果,但它表明双精度也无法解决您的问题。


1
如果你将 printf("%f (%d)\n", offsetX, result); 改为 printf("%.8f (%d)\n", offsetX, result);,你会看到问题。做出这个更改后,输出为:
6.99999952 (6)

你可以通过四舍五入而不是强制转换为int来纠正这个问题。也就是说,将result = (int)offsetX;更改为result = roundf(offsetX);。不要忘记#include <math.h>。现在,输出为:

6.99999952 (7)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接