5

我刚刚在 Objective-C 中遇到了一种情况:

NSLog(@"%i", (int) (0.2 * 10));         // prints 2
NSLog(@"%i", (int) ((1.2 - 1) * 10));   // prints 1

所以我想知道,如果值是浮点数或双精度数,并且我们想要一个整数,我们不应该只使用(int)来进行转换,而是使用(int) round(someValue)? 或者,换个角度来说,我们什么时候应该使用(int),但在那些情况下,不能(int) round(someValue)也可以完成这项工作,所以我们几乎应该总是使用(int) round(someValue)?

4

3 回答 3

3

这里的问题不是将浮点值转换为整数,而是浮点数出现的舍入错误。当你使用浮点时,你应该很好地理解它。

float 和 double 的常见实现使用 IEEE 754 二进制浮点值。这些值表示为有效数字乘以 2 的幂乘以符号(+1 或 -1)。对于浮点数,有效数字是 24 位二进制数字,在“小数点”(或“二进制点”,如果您愿意)之前有一位。例如,数字 1.25 的有效数字为 1.010000000000000000000000。对于双精度数,有效数字是 53 位二进制数字,点前有一位。

因此,十进制数字 .1 和 1.1 的值无法准确表示。它们必须是近似的。当您在源代码中写入“.1”或“1.1”时,编译器会将其转换为非常接近实际值的双精度值。有时该结果会略大于实际值。有时它会略低于实际值。

当您将 float 转换为 int 时,结果(根据定义)仅为值的整数部分(该值被截断为零)。因此,如果您的值略大于正整数,您将获得整数。如果你的值略小于一个正整数,你会得到下一个较小的整数。

如果您期望精确的数学会给您一个整数结果,并且您正在执行的浮点运算如此之少且如此简单以至于错误没有累积太多,那么您可以将浮点值四舍五入为整数,使用轮函数。在简单的情况下,您还可以通过在截断前添加 0.5 进行舍入,例如写“(int) (f + .5)”。

于 2012-06-27T15:34:36.500 回答
1

这取决于你想要什么。显然,直接转换 toint比调用 to 更快round,而 round 会给出更准确的值。

除非您正在编写依赖于速度才能有效的代码(在这种情况下,浮点值可能也不是最好的使用),否则我会说调用round. 即使它仅将您在屏幕上显示的内容改变一个像素,在处理某些事物(角度测量、颜色等)时,您可以获得的精度越高越好。

编辑:简单的测试来支持我关于铸造比四舍五入更快的说法:

在 Macbook Pro 上测试:

  • 2.8 GHz 英特尔酷睿 2 双核
  • Mac OS 10.7.4
  • 苹果 LLVM 3.1 编译器
  • -O0(无优化)

代码:

int value;
void test_cast()
{
    clock_t start = clock();
    value = 0;
    for (int i = 0; i < 1000 * 1000; i++)
    {
        value += (int) (((i / 1000.0) - 1.0) * 10.0);
    }

    printf("test_cast: %lu\n", clock() - start);
}

void test_round()
{
    clock_t start = clock();
    value = 0;
    for (int i = 0; i < 1000 * 1000; i++)
    {
        value += round(((i / 1000.0) - 1.0) * 10.0);
    }

    printf("test_round: %lu\n", clock() - start);
}

int main()
{
    test_cast();
    test_round();
}

结果:

测试演员:11895
测试轮:14353

注意:我知道这clock()不是最好的分析功能,但它确实表明round()至少使用了更多的 CPU 周期。

于 2012-06-27T14:59:26.460 回答
0

转换为 int 会将 float 或 double 值舍入为零。

1.1 -> 1, 1.99999999999 -> 1, 2.0 -> 2

-1.1 -> -1, -1.999999999 -> -1, -2 -> -2

那是你要的吗?如果是,那就是你应该做的。如果没有,你想要什么?

浮点运算总是会产生舍入误差。因此,例如 0.2 * 10 将给出一个接近 2 的数字。可能会少一点,或者多一点,或者纯粹是偶然,它可能正好是 2。因此 (int) (0.2 * 10) 可能是1 或 2,因为“略小于 2”将转换为 1。

round (x) 将四舍五入到最接近的整数。同样,如果你计算取整 (1.4 + 0.1),1.4 和 0.1 的总和是一个非常接近 1.5 的数字,可能会少一点,也可能会多一点,所以你不知道它是四舍五入到 1.0 还是 2.0 .

您是否希望将 1.5 到 2.5 的所有数字四舍五入为 2?使用 (int) 圆 (x)。如果 x 为 1.5 或 2.5,您可能会得到稍微不同的结果。也许您希望将最大为 1.9999 的数字向下舍入,但将 1.99999999 四舍五入为 2。使用双精度数,而不是浮点数,并计算 (int) (x + 0.000001)。

于 2014-02-28T23:30:25.827 回答