【问题标题】:iphone / Objective C - Comparing doubles not workingiphone / Objective C - 比较双打不起作用
【发布时间】:2011-01-19 07:13:32
【问题描述】:

我想我快疯了。 “计数器”和“间隔”都是双打。这发生在 accelerometer: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) );

【问题讨论】:

  • 是的,事实证明就是这样。虽然这似乎是相反的问题,但我使用了 float 类型并且它有效。谢谢赛斯
  • 你不应该依赖float/double。使用 float 可以解决这个问题,但会在另一种情况下中断。尝试找出更好的解决方案。在许多情况下,使用 >= 而不是 == 可能会解决问题。
  • 哇.. 是的,使用浮点数最终也不起作用。来自 AS3 和 JS,我真的不知道。谢谢大家。会更加努力地阅读浮点 wiki 页面。
  • 根据 IEEE 754 而非特定语言来考虑双精度和浮点数。 IEEE 754 不保证两个浮点值相等(在== 意义上),即使您希望它们具有相同的值。使用这样的增量比较:if (fabs(counter - interval) < SOME_SMALL_ENOUGH_VALUE) ...;

标签: iphone objective-c ios floating-point


【解决方案1】:

永远不要将双精度数或浮点数与相等性进行比较 - 它们可能看起来与您正在检查的有效数字的数量相同,但计算机会看到更多。

为此,Foundation Framework 为“float”和“double”等不同类型提供了“epsilon”值。如果两个数之间的距离小于 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

【讨论】:

  • 这是 IMO 的最佳方法。
  • DBL_EPSILON 对我来说不够准确,仍然给出了假阴性。我必须指定一个偏移量,如 0.000001
【解决方案2】:

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

0.01000000000000000020816681711721685132943093776702880859375

不出所料,当您反复将此值添加到自身时,您永远不会准确地得到 0.5

两个选项:更好的是将if 条件替换为(counter &gt;= interval)。或者,您可以使用 2 的小幂来代替无法表示的值,例如 0.0078125

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多