2016-01-25 3 views
0

Je suis venu un comportement étrange de NSNumber.NSNumber n'est pas le même que son floatValue

essentiellement mon code obtient JSON appel API:

id json_response = [NSJSONSerialization 
          JSONObjectWithData:data 
          options:NSJSONReadingMutableLeaves 
          error:&error]; 

et stocké NSDictionary

puis je me suis NSNumber de et en utilisant NSNumberFormatter pour le convertir en une chaîne, mais ...

NSNumber * avgNumber = [[_tableDataArray objectAtIndex:index ] 
          objectForKey:kTrendsKeyAvgScoreFloat]; 

est ici la sortie de formatage:

NSNumberFormatter * formatter = [[NSNumberFormatter alloc]init]; 
[formatter setDecimalSeparator:@","]; 
[formatter setMaximumFractionDigits:1]; 
[formatter setMinimumFractionDigits:0]; 
[formatter setGroupingSeparator:@"."]; 
[formatter setGroupingSize:3]; 
[formatter setNumberStyle:NSNumberFormatterDecimalStyle]; 
NSString * retString = [formatter stringFromNumber:number]; 

je suis arrivé un comportement étrange quand NSNumber a une valeur de 1,05

(__NSCFNumber *) avgNumber = 0x0000000155923800 (float)1.050000 

Mais avec le code ci-dessus, il a été l'impression (au lieu de prévu 1.1):

1 

Cependant, lorsque j'ai vérifié valeur flottante

float avg = [avgNumber floatValue]; 

il s'avère que

Printing description of avg: 
(double) avg = 1.0499999523162842 

Même si j'essaie d'arrondir à 2 chiffres après la virgule

avg = roundf(avg * 100); // here 105 
    avg = avg/100; // and here is 1.0499999523162842 again 

Toutefois, si je teste le code et mis 1,05 manuellement à l'intérieur NSDictionary tout fonctionne comme prévu.

Si quelqu'un pouvait expliquer pourquoi? Et comment préserver chaque fois bon affichage?

+0

Ce n'est pas clair quel est votre problème. Est-ce que 'NSNumberFormatter' produit' 1' au lieu de '1.1'? Dans ce cas, c'est parce qu'il arrondit vers le bas. Ou êtes-vous confus par le nombre étant «1.04999» au lieu de «1.05»? Dans ce cas, c'est juste une erreur d'arrondi à virgule flottante. – trojanfoe

+1

http://floating-point-gui.de –

+0

Oui, je suis confus parce que j'ai 1.05 et il devrait être arrondi à 1.1 pas 1. – mazziek

Répondre

4

Le problème est qu'une valeur de 1,05 ne peut pas être représentée exactement par un nombre à virgule flottante. Ceci n'est possible que pour des valeurs qui sont des sommes de puissances (positives ou négatives) de 2. On peut donc représenter exactement des valeurs comme 1 (= 2^0) ou 1.03125 (= 2^0 + 2^-5), mais la meilleure approximation à 1.5 est dans votre cas 1.0499999523162842.
Maintenant, lorsque vous initialisez un NSNumberFormatter, et ne pas définir sa propriété roundingMode, sa valeur par défaut est kCFNumberFormatterRoundHalfEven, ce qui signifie que le nombre sera arrondi « vers entier le plus proche ou vers un numéro, même si à égale distance. »
Donc, si votre le numéro est 1.0499999523162842, il sera arrondi à 1.0, et ce résultat est égal à 1.

+0

c'est parfaitement clair pour moi, merci. Alors, comment montrer le nombre approprié à l'utilisateur final? Parce que même en utilisant le mode d'arrondi correct ne va pas aider car il arrondira 1.0499999523162842 pas 1.05 – mazziek

+0

Si vous voulez arrondir non pas vers un entier, mais vers la moitié d'un entier (dans votre cas vers 1,05), vous pouvez faire: Si x est la valeur à arrondir, arrondir 2x à un entier et diviser le résultat par 2. 1,0499 * 2 = 2,0998, arrondi = 2,1/2 = 1,05.Mais, comme nous l'avons dit, 1,05 ne peut pas être exprimé exactement par un nombre à virgule flottante. –