objective-c - 在 C 和 Objective-C 中,将 float 或 double 截断为整数的真正正确方法是什么?

标签 objective-c c floating-point floating-accuracy

我之前主要使用整数,在需要将 float 或 double 截断为整数的情况下,我之前会使用以下内容:

(int) someValue

除非我发现以下内容:

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

(请参阅 Strange behavior when casting a float to int in C# 的解释)。

简短的问题是:我们应该如何截断一个 float 或 double 来正确地转换为整数? (在这种情况下需要截断,而不是“舍入”)。或者,我们可以说,由于一个数字是 1.9999999999999,另一个是 2.00000000000001(粗略地说),截断实际上是正确完成的。所以问题是,我们应该如何转换 float 或 double,以便结果是一个具有常见用法意义的“截断”数字?

(目的是不使用 round,因为在这种情况下,对于 1.8,我们确实想要 1 的结果,而不是2)


较长的问题:

我用过

int truncateToInteger(double a) {
    return (int) (a + 0.000000000001);
}

-(void) someTest {
    NSLog(@"%i", truncateToInteger((1.2 - 1) * 10));
    NSLog(@"%i", truncateToInteger((1.2f - 1) * 10));
}

并且都打印为 2,但这似乎太过分了,我们应该使用多少小数字来“消除不准确”?有没有更标准或经过研究的方法,而不是这种任意的 hack?

(注意在某些用法中我们要截断,而不是四舍五入,例如,如果秒数是 90 或 118,当我们显示经过了多少分钟和多少秒时,分钟应该显示为 1,但不应四舍五入为 2)

最佳答案

当然,截断已正确执行,但中间值不准确。

通常没有办法知道您的 1.999999 结果是否稍微不准确 2(因此截断后的精确数学结果是 2),或者稍微不准确的 1.999998(因此截断后的精确数学结果为 1)。

就此而言,对于某些计算,您可能会得到 2.000001 作为稍微不准确的 1.999998。几乎无论你做什么,你都会弄错那个。截断是一个非连续函数,因此无论您如何操作,它都会使您的整体计算在数值上不稳定。

无论如何您都可以添加任意公差:(int)(x > 0 ? x + epsilon : x - epsilon)。它可能有帮助,也可能没有帮助,这取决于你在做什么,这就是为什么它是一个“黑客”。 epsilon 可以是常数,也可以根据 x 的大小进行缩放。

第二个问题的最常见解决方案不是“消除不准确”,而是接受不准确的结果,就好像它是准确的一样。因此,如果您的浮点单元表示 (1.2-1)*10 是 1.999999,那么,它 1.999999。如果该值表示分钟数,则它会截断为 1 分 59 秒。您最终显示的结果将与真实值相差 1 秒。如果您需要比这更准确的最终显示结果,那么您不应该使用浮点运算来计算它,或者您应该在截断为分钟之前四舍五入到最接近的秒。

任何尝试从 float 中“消除”不准确性实际上只会改变不准确性 - 一些输入会给出更准确的结果,而另一些则不太准确。如果您足够幸运,可以将不准确性转移到您不关心的输入中,或者可以在进行计算之前过滤掉,那么您就赢了。但总的来说,如果你必须接受任何输入,那么你就会在某个地方迷路。您需要研究如何使您的计算更准确,而不是试图在最后的截断步骤中消除不准确。

您的示例计算有一个简单的更正 - 使用以 10 为底的小数位的定点算术。我们知道 format 可以准确表示 1.2。因此,您不应编写 (1.2 - 1) * 10,而应重新调整计算以使用十分之一(编写 (12 - 10) * 10),然后除以最终结果结果乘以 10 以将其缩放回单位。

关于objective-c - 在 C 和 Objective-C 中,将 float 或 double 截断为整数的真正正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11244713/

相关文章:

ios - 根据包含背景图像的文本的宽度拉伸(stretch) UILabel 的宽度

c - 如何修复将 'char [16]' 传递给类型为 'FILE *'(又名 'struct __sFILE *')的参数的不兼容指针类型 [-Wincompatible-pointer-types]

java - 算术比较以避免浮点错误

algorithm - 数学库中的除法函数如何处理除法运算符无法做到的精度误差?

iphone - 如何在自定义单元格中找到按钮框架的 x , y 位置

iphone - NSString 长度限制

ios - 如何使图像和字符串的单个数组?在IOS中

c - c中的int指针和char指针有区别吗?

C语言计算2的最高次幂整除一个数

c++ - 当我们在 C++ 中划分两个数组的整数时,如何在 float 中进行计算;