2011-01-19 14 views
7

Myślę, że zwariuję. "counter" i "interval" są podwójne. Dzieje się to na akcelerometrze: didAccelerate w przedziale (.01). "licznik" powinien ostatecznie zwiększyć się do "przedziału". Z jakiegoś powodu nie mogę uzyskać tego "jeśli", aby zadzwonić prawdę.iphone/Cel C - Porównanie debla nie działa

Czy coś przeoczyłem?

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)); 
+1

możliwy duplikat [Trouble with Float w Objective-c \ [SOLVED \]] (http://stackoverflow.com/questions/1193554/trouble-with-float-inobjective-c- solve) – Seth

+0

Tak, okazuje się być po prostu tym. Choć wydaje się, że jest to odwrotny problem, użyłem typu float i zadziałało. Dzięki Seth – azeven

+1

Nie powinieneś polegać na float/double. Użycie funkcji float może rozwiązać ten problem, ale spowoduje jego uszkodzenie w innej sytuacji. Spróbuj wymyślić lepsze rozwiązania. Używanie> = zamiast == może rozwiązać w wielu przypadkach. – taskinoor

Odpowiedz

2

W swoim bloku else, nie dodajesz 0.01 przeciwdziałać, ponieważ nie jest to reprezentowalna wartość podwójnej precyzji. Jesteś rzeczywiście dodając wartość:

0.01000000000000000020816681711721685132943093776702880859375 

zaskoczeniem, kiedy wielokrotnie dodać tę wartość do siebie, że nigdy nie dostać 0.5 dokładnie.

Dwie opcje: im lepiej wymienić stan if na (counter >= interval). Alternatywnie możesz użyć małej mocy dwóch dla przyrostu zamiast czegoś, co nie może być reprezentowane, na przykład 0.0078125.

17

Nigdy nie porównuj podwójnych ani pławików z równością - mogą wyglądać tak samo na podstawie liczby ważnych cyfr, które analizujesz, ale komputer widzi więcej.

W tym celu Framework Foundation dostarcza wartości "epsilon" dla różnych typów, takich jak "float" i "double". Jeśli odległość między dwiema liczbami jest mniejsza niż epsilon, możesz założyć, że te dwie liczby są równe.

W twoim przypadku, należy używać go w sposób następujący:

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

albo w Swift 4:

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

Dwa bardzo przydatne linki:

What Every Computer Scientist Should Know About Floating-Point Arithmetic

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

+0

To jest najlepsze podejście IMO. – Chuck