2011-10-29 16 views
9

Parece que encuentro un problema extraño en Objective-C convirtiendo un flotador en un NSNumber (envolviéndolo por conveniencia) y luego convirtiéndolo de nuevo en un flotador .Pérdida de precisión convirtiendo 'float' en NSNumber, volviendo a 'float'

En pocas palabras, una clase de mina tiene una propiedad red, que es un flotador de 0.0 a 1.0:

@property (nonatomic, assign) float red; 

Este objeto está comparando sí mismo a un valor que se carga desde el disco, para fines de sincronización . (El archivo puede cambiar fuera de la aplicación, por lo que comprueba periódicamente si hay cambios en los archivos, carga la versión alternativa en la memoria, y hace una comparación, la fusión de las diferencias.)

He aquí un fragmento interesante en el que se comparan los dos valores:

if (localObject.red != remoteObject.red) { 
    NSLog(@"Local red: %f Remote red: %f", localObject.red, remoteObject.red); 
} 

Esto es lo que veo en los registros:

2011-10-28 21:07:02.356 MyApp[12826:aa63] Local red: 0.205837 Remote red: 0.205837 

extraño. ¿Derecha? ¿Cómo se está ejecutando este fragmento de código?

El valor real tal como se almacena en el archivo:

...red="0.205837"... 

se convierte en un float usando:

currentObject.red = [[attributeDict valueForKey:@"red"] floatValue]; 

En otro punto en el código yo era capaz de enganchar una captura de pantalla de GDB. Se imprimió a NSLog como: (Esta es también la precisión con la que aparece en el archivo en el disco.)

2011-10-28 21:21:19.894 MyApp[13214:1c03] Local red: 0.707199 Remote red: 0.707199 

Pero aparece en el depurador como:

GDB Screenshot

cómo es esto nivel de precisión que se obtiene en el nivel de propiedad, pero que no se almacena en el archivo ni se imprime correctamente en NSLog? ¿Y por qué parece variar?

+0

Podría haber encontrado algo aquí, pero no apareció en ninguna búsqueda anterior desafortunadamente: http://stackoverflow.com/questions/5024913/issue-with-float-and-double-data-types-in- objetivo-c/5025021 # 5025021 –

+1

¿Lo está convirtiendo a/de una cadena en cualquier punto? Si es así, use '% + 0.16f' en lugar de'% f'. O cualquiera que sea la precisión que desee en lugar de '.16'. Si no, ignore este comentario). – chown

+0

Sí, estoy convirtiéndolo absolutamente en/desde un NSString. Sin embargo, había asumido que al crearlo: ** [NSString stringWithFormat: @ "% f", 0.707199f] ** y luego convertirlo como: ** [... floatValue] ** daría como resultado el mismo valor. Supongo que no. Gracias por el consejo, imagino que eso aclarará las cosas. Siéntase libre de publicarlo como una respuesta. –

Respuesta

5

Si va a convertir a/desde una cadena en cualquier punto de tratar de usar en lugar de %0.16f%f (o lo que sea de precisión que desea en lugar de .16).

Para obtener más información, consulte IEEE Std formatting.


Asimismo, el uso objectForKey en lugar de valueForKey (valueForKey no está destinado a ser utilizado en los diccionarios):

currentObject.red = [[attributeDict objectForKey:@"red"] floatValue]; 

Ver esta respuesta para una mejor explicación de objectForKey vs valueForKey:

Difference between objectForKey and valueForKey?

+0

¡Gracias, eso funciona! También gracias por objectForKey: nota, generalmente vigilo más de cerca esas cosas. –

+0

@craig Np, ¡me alegro de poder ayudar! – chown

3

El problema que está experimentando es un problema con el punto flotanteUn número de punto flotante no representa exactamente el número almacenado (excepto en algunos casos específicos que no importan aquí). El ejemplo en el enlace craig posted es un excelente ejemplo de esto.

En su código, cuando escribe el valor de su archivo, escribe una aproximación de lo que está almacenado en el número de coma flotante. Cuando lo carga de nuevo, se almacena otra aproximación en el flotador. Sin embargo, es poco probable que estos dos números sean iguales.

La mejor solución es utilizar una comparación difusa de los dos números de coma flotante. No soy un programador objetivo, así que no sé si los idiomas incluyen funciones integradas para realizar esta comparación. Sin embargo, this link proporciona un buen conjunto de ejemplos sobre diversas formas de realizar esta comparación.

También puede probar la otra solución publicada de usar una mayor precisión para escribir en su archivo, pero probablemente perderá espacio para la precisión extra que no necesita. Personalmente, te recomiendo que uses la comparación difusa, ya que es más a prueba de balas.

0
+3

Si bien esto puede responder teóricamente a la pregunta, [sería preferible] (http://meta.stackexchange.com/q/8259) incluir aquí las partes esenciales de la respuesta y proporcionar el enlace de referencia. –

2

Usted dice que el valor de "a distancia" se "carga desde el disco". Supongo que la representación en el disco no es un valor de bit flotante IEEE, sino más bien algún tipo de representación de caracteres o algo así. Por lo tanto, existen inevitables errores de conversión que van desde y hacia esa representación, dado el funcionamiento del flotador IEEE. No obtendrás un resultado exacto, dado que solo hay unos 6 dígitos de precisión decimal en un valor flotante, pero raramente se asigna a exactamente 6 dígitos decimales, pero en su lugar es como representar 1/3 en decimal, no hay un valor exacto cartografía.