iphone / Objective C - 比较双打不起作用

时间:2011-01-19 07:13:33

标签: iphone objective-c ios floating-point

我想我会疯了。 “反击”和“间隔”都是双打。这发生在加速度计上:didAccelerate,间隔为(.01)。 “计数器”最终应增加到“间隔”。由于某种原因,我不能得到这个“如果”响。

我忽略了什么吗?

double interval = .5;
 if( counter == interval ){ //should eventually be .50000 == .50000
  NSLog( @"Hit!" );
  [self playSound];
  counter = 0;
 }else{
  counter += .01;
 }
NSLog( @"%f, %f, %d",counter,interval,(counter == interval) );

2 个答案:

答案 0 :(得分:22)

不要将双打或花车与平等进行比较 - 它们可能看起来与您正在检查的有效数字相同但计算机看得更多。

为此,Foundation Framework为不同类型提供“epsilon”值,例如“float”和“double”。如果两个数字之间的距离小于epsilon,则可以假设这两个数字相等。

在您的情况下,您可以按照以下方式使用它:

- (BOOL)firstDouble:(double)first isEqualTo:(double)second {
    if(fabs(first - second) < DBL_EPSILON)
        return YES;
    else
        return NO;
}

或者在Swift 4中:

func doublesAreEqual(first: Double, second: Double) -> Bool {
    if fabs(first - second) < .ulpOfOne {
        return true
    }
    return false
}

两个非常有用的链接:

What Every Computer Scientist Should Know About Floating-Point Arithmetic

Interesting discussion of Unit in Last Place (ULP) and usage in Swift

Friday Q&A 2011-01-04: Practical Floating Point

答案 1 :(得分:2)

else块中,您没有向计数器添加0.01,因为这不是可表示的双精度值。您实际上是在添加值:

0.01000000000000000020816681711721685132943093776702880859375

不出所料,当您反复将此值添加到自身时,您永远不会完全获得0.5

两个选项:更好的方法是将if条件替换为(counter >= interval)。或者,你可以使用两个小的幂来增加,而不是像0.0078125那样无法表示的东西。