tags:

views:

4291

answers:

5

Hi, I'm building a app that needs to perform calculations on money.

I wonder how to properly use NSDecimalNumber, especially how to initialize it from integers, floats & doubles?

I only found it easy to use the -decimalNumberWithString: method. The -initWith... methods are discouraged so that only left the ones with mantissa, but never in any of 7 languages I used before did I need that so I don't know what put there...

A: 

You can use [NSDecimalNumber numberWithInt:myint] or similar. See the documentation for NSNumber, which is NSDecimalNumber's superclass.

Ben Alpert
Do not use NSNumber's methods to create NSDecimalNumber objects. They are typed to return NSNumber objects and using them as NSDecimalNumber's is inappropriate.
Ashley Clark
A: 

As suggested everywhere, NSDecimalNumber is the way to go for money in Obj-c. I will sell it globally so i can't fix the number of decimals.

mamcx
A: 

Using [NSDecimalNumber numberWithInt:myint] produce a warning.

mamcx
+10  A: 

Do NOT use NSNumber's +numberWith... methods to create NSDecimalNumber objects. They are declared to return NSNumber objects and are not guaranteed to function as NSDecimalNumber instances.

This is explained in this thread by Bill Bumgarner, a developer at Apple. I would encourage you to file a bug against this behavior, referencing bug rdar://6487304.

As an alternative these are all of the appropriate methods to use to create an 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;

If you simply want an NSDecimalNumber from a float or int constant try something like this:

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

Design-wise, you should try to avoid converting NSDecimalNumber or NSDecimals to and from int, float, and double values for the same reasons it's recommended you use NSDecimalNumbers: loss of precision and binary floating point representation issues. I know, sometimes it's unavoidable (taking input from a slider, doing trigonometric calculations, etc.), but you should try to take input from users as NSStrings and then use initWithString:locale: or decimalNumberWithString:locale: to generate the NSDecimalNumbers. Do all your math with the NSDecimalNumbers and return their representation to users or save them to SQLite (or wherever) as their string description using descriptionWithLocale:.

If you have to input from an int, float, or double, you could do something like the following:

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

or you could follow Ashley's suggestion to make sure you're safe in the decimal construction.

Brad Larson