2011-01-19 10 views
7

Creo que me estoy volviendo loco. "contador" e "intervalo" son ambos dobles. Esto está sucediendo en el acelerómetro: didAccelerate en un intervalo de (.01). "contador" debería eventualmente incrementarse a "intervalo". Por alguna razón, no puedo hacer que este "si" suene verdadero.iphone/Objetivo C - Comparando los dobles no funcionan

¿Estoy pasando por alto algo?

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

posible duplicado de [Problema con flotación en Objective-c \ [SOLUCIONADO]] (http://stackoverflow.com/questions/1193554/trouble-with-float-in-objective-c-solved) – Seth

+0

Sí, resulta que para ser solo eso. Aunque parece ser el problema inverso, utilicé el tipo de flotador y funcionó. Gracias Seth – azeven

+1

No debe confiar en flotador/doble. Usar float puede resolver este, pero se romperá en otra situación. Intenta descubrir mejores soluciones. Usar> = en vez de == puede resolver en muchos casos. – taskinoor

Respuesta

2

En su bloque else, no va a agregar 0.01 para contrarrestar, porque eso no es un valor de doble precisión representable. En realidad se está agregando el valor:

0.01000000000000000020816681711721685132943093776702880859375 

Como era de esperar, al agregar varias veces este valor en sí mismo, nunca se tiene 0.5 exactamente.

Dos opciones: la mejor es reemplazar la condición if con (counter >= interval). Alternativamente, puede usar una pequeña potencia de dos para el incremento en lugar de algo que no se puede representar, como 0.0078125.

17

No compare nunca dobles o flotantes con igualdad: pueden parecer iguales en el número de cifras significativas que está examinando pero la computadora ve más.

Para este propósito, Foundation Framework proporciona valores "epsilon" para diferentes tipos como "float" y "double". Si la distancia entre dos números es menor que épsilon, puede suponer que estos dos números son iguales.

En su caso, se utilizaría como sigue:

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

O en Swift 4:

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

dos enlaces muy útiles:

What Every Computer Scientist Should Know About Floating-Point Arithmetic

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

+0

Este es el mejor enfoque de la OMI. – Chuck