2010-09-16 3 views
0

J'utilise NSNumber pour stocker diverses valeurs, mais je rencontre parfois des problèmes lorsque je fais des calculs avec les valeurs et que j'initialise de nouveaux objets NSNumber pour les résultats. J'ai compris comment le surmonter, mais je ne pouvais pas pour la vie de moi expliquer pourquoi cela fonctionne et comme ma compréhension des valeurs numériques dans les environnements informatiques (doubles, flotteurs, etc) est faible, je voudrais demander à cette question à apprendre. :-)Problème avec NSNumber -initWithDouble et les valeurs résultantes

Le premier exemple est quand je convertis entre différentes unités de mesure, dans ce cas particulier c'est entre mmol/L et mg/dl. Obtenir un NSNumber qui représente une valeur mmol/L, j'extraire sa valeur double et effectuer le calcul. Ensuite, je crée un nouveau NSNumber avec -initWithDouble et retourne le résultat.

Cependant, je reçois des bizarreries bizarres. Si la valeur mmol/L est de 10,0, la valeur mg/dl correspondante est de 180,0 (le taux, évidemment, est simplement de 18). Mais quand je devrai par la suite laisser l'utilisateur sélectionner une nouvelle valeur dans un sélecteur et utiliser NSNumber -intValue pour obtenir les chiffres entiers de la valeur courante (en utilisant ma propre extension pour obtenir les chiffres fractionnaires), l'int est 179! J'ai vérifié toutes les valeurs doubles intermédiaires pendant le calcul ainsi que la double valeur du nouveau NSNumber et tout va bien (180.00000 est le résultat). Fait intéressant, cela ne se produit pas pour toutes les valeurs, seulement quelques-unes (10.0 étant un exemple réel).

Le deuxième exemple est lorsque je récupère des valeurs doubles à partir d'une base de données Sqlite3 et les stocke dans NSNumbers. Encore une fois, la plupart des valeurs fonctionnent bien, mais parfois je reçois des choses bizarres. Par exemple, si j'économise 6.7 dans la base de données (en vérifiant quand il est enregistré que c'est bien la valeur), ce que mon NSNumber montrera après la récupération est 6.699999. (Je ne peux pas me rappeler au moment de l'écriture si c'est aussi le cas dans la base de données, mais je pense que - je peux vérifier plus tard.)

Ces deux instances peuvent être contournées en utilisant une valeur intermédiaire et NSNumber initWithFloat au lieu de initWithDouble. Donc, dans ma conversion, par exemple, je fais juste un float resultAsFloat = resultAsDouble et j'utilise initWithFloat pour le nouveau NSNumber.

Excuses pour la question à long terme et si c'est juste ma propre connaissance de travailler avec des valeurs numériques qui manque, mais j'apprécierais vraiment si quelqu'un pourrait m'expliquer cela!

Merci,

Anders

* EDIT 1 *

Code pour l'exemple de conversion d'unité:

-(NSNumber *)convertNumber:(NSNumber *)aNumber withUnit:(FCUnit *)aUnit { 

// if origin unit and target unit are the same, return original number 
if ([aUnit.uid isEqualToString:self.target.uid]) 
    return aNumber; 

// determine if origin unit and target unit are comparable 
if (aUnit.quantity != self.target.quantity) 
    return nil; 

// if so, convert the number... 

// get bases 
double originBase; 
double targetBase; 
if (aUnit.metre != nil) { 

    originBase = [aUnit.metre doubleValue]; 
    targetBase = [self.target.metre doubleValue]; 

} else if (aUnit.kilogram != nil) { 

    originBase = [aUnit.kilogram doubleValue]; 
    targetBase = [self.target.kilogram doubleValue]; 

} else if (aUnit.second != nil) { 

    originBase = [aUnit.second doubleValue]; 
    targetBase = [self.target.second doubleValue]; 

} else if (aUnit.quantity == FCUnitQuantityGlucose) { 

    // special case for glucose 

    if ([aUnit.uid isEqualToString:FCKeyUIDGlucoseMillimolesPerLitre]) { // mmol/L -> mg/dl 

     originBase = 1; 
     targetBase = 0.0555555555555556; // since 1/0.0555555555555556 = 18 

    } else if ([aUnit.uid isEqualToString:FCKeyUIDGlucoseMilligramsPerDecilitre]) { // mg/dl -> mmol/L 

     originBase = 0.0555555555555556; 
     targetBase = 1; 
    } 
} 

// find conversion rate 
double rate = originBase/targetBase; 

// convert the value 
double convert = [aNumber doubleValue] * rate; 

// TMP FIX: this fixes an issue where the intValue of convertedNumber would be one less 
// than it should be if the number was created with a double instead of a float. I have 
// no clue as to why... 
float convertAsFloat = convert; 

// create new number object and return it 
NSNumber *convertedNumber = [[NSNumber alloc] initWithFloat:convertAsFloat]; 
[convertedNumber autorelease]; 

return convertedNumber; 
} 
+1

Pourriez-vous nous indiquer le code? – tia

+0

Bien sûr. J'ai ajouté le code pour l'exemple de conversion d'unité dans mon article ci-dessus. – Ansig

Répondre

0

Si je ne me trompe pas et si je me souviens bien du cours approprié au collège je pense qu'il est une question de conversion de la réalité (où vous avez des valeurs infinies) au virtuel (où vous avez des valeurs finies même si vous en avez beaucoup): vous ne pouvez donc pas réellement représenter TOUS les nombres. Vous devez aussi faire face aux opérations que vous effectuez: les multiplications et les divisions génèrent beaucoup de problèmes, car vous aurez beaucoup de nombres décimaux et, à mon avis, les langages C-Based ne sont pas les meilleurs pour gérer ça. genre de matière. En espérant que cela vous dirigera vers une meilleure source d'information :).

Questions connexes