web-dev-qa-db-fra.com

Comment utiliser NSDecimalNumber?

Je construis une application qui doit effectuer des calculs d'argent.

Je me demande comment utiliser correctement NSDecimalNumber, en particulier comment l'initialiser à partir d'entiers, de flottants et de doubles?

J'ai seulement trouvé facile d'utiliser la méthode -decimalNumberWithString:. Les méthodes -initWith... sont déconseillées de manière à ne laisser que celles avec mantisse, mais jamais dans les 7 langues que j'ai utilisées auparavant, j'en avais besoin, alors je ne sais pas ce qui est mis là-bas ...

43
mamcx

Ne PAS utilisez les méthodes +numberWith... de NSNumber pour créer des objets NSDecimalNumber. Ils sont déclarés comme retournant des objets NSNumber et il n'est pas garanti qu'ils fonctionnent comme des instances NSDecimalNumber.

Ceci est expliqué dans ce thread par Bill Bumgarner, développeur chez Apple. Je vous encourage à signaler un bogue contre ce problème, en faisant référence au bogue rdar: // 6487304.

En guise d'alternative, ce sont toutes les méthodes appropriées à utiliser pour créer un NSDecimalNumber:

+ (NSDecimalNumber *)decimalNumberWithMantissa:(unsigned long long)mantissa
                     exponent:(short)exponent isNegative:(BOOL)flag;
+ (NSDecimalNumber *)decimalNumberWithDecimal:(NSDecimal)dcm;
+ (NSDecimalNumber *)decimalNumberWithString:(NSString *)numberValue;
+ (NSDecimalNumber *)decimalNumberWithString:(NSString *)numberValue locale:(id)locale;

+ (NSDecimalNumber *)zero;
+ (NSDecimalNumber *)one;
+ (NSDecimalNumber *)minimumDecimalNumber;
+ (NSDecimalNumber *)maximumDecimalNumber;
+ (NSDecimalNumber *)notANumber;

Si vous voulez simplement une constante NSDecimalNumber à partir d'une constante float ou int, essayez ceci:

NSDecimalNumber *dn = [NSDecimalNumber decimalNumberWithDecimal:
                             [[NSNumber numberWithFloat:2.75f] decimalValue];
82
Ashley Clark

La bonne façon est en fait de faire ceci:

NSDecimalNumber *floatDecimal = [[[NSDecimalNumber alloc] initWithFloat:42.13f] autorelease];
NSDecimalNumber *doubleDecimal = [[[NSDecimalNumber alloc] initWithDouble:53.1234] autorelease];
NSDecimalNumber *intDecimal = [[[NSDecimalNumber alloc] initWithInt:53] autorelease];

NSLog(@"floatDecimal floatValue=%6.3f", [floatDecimal floatValue]);
NSLog(@"doubleDecimal doubleValue=%6.3f", [doubleDecimal doubleValue]); 
NSLog(@"intDecimal intValue=%d", [intDecimal intValue]);

Voir plus d'infos ici .

31
orj

En ce qui concerne la conception, évitez de convertir NSDecimalNumber ou NSDecimals en valeurs int, float et double pour les mêmes raisons, il est recommandé d’utiliser NSDecimalNumbers: perte de précision et problèmes de représentation en virgule flottante binaire. Je sais que, parfois, c'est inévitable (prendre les entrées d'un curseur, faire des calculs trigonométriques, etc.), mais vous devriez essayer de prendre les utilisateurs comme NSStrings, puis utiliser initWithString: locale: ou decimalNumberWithString: locale: pour générer NSDecimalNumbers. Faites tous vos calculs avec NSDecimalNumbers et renvoyez leur représentation aux utilisateurs ou sauvegardez-les dans SQLite (ou ailleurs) en tant que description de chaîne à l'aide de descriptionWithLocale :.

Si vous devez entrer un int, un float ou un double, vous pouvez faire quelque chose comme ceci:

int myInt = 3;
NSDecimalNumber *newDecimal = [NSDecimalNumber decimalNumberWithString:[NSString stringWithFormat:@"%d", myInt]];

ou vous pouvez suivre la suggestion d'Ashley pour vous assurer que vous êtes en sécurité dans la construction décimale.

6
Brad Larson

Un petit ajout: si vous initiez NSDecimalNumber à partir d'une chaîne, il pourrait être utile de définir également une langue Par exemple, si votre chaîne contient une virgule en tant que decimal separator

self.order.amount = [NSDecimalNumber decimalNumberWithString:self.amountText locale:[NSLocale currentLocale]];
0
wzbozon