Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using NSDecimalNumber in objective-c

I have a calculation that goes something like this:

Price = value * randomNumberBetween(decimalValueA, decimalValueB)

I was originally generating this using floats/doubles. However, after looking up a bit more on objective-c, it was mentioned numerous times that when calculating currency you should use NSDecimalNumber. The issue I have is that I use this 'price' variable in comparisons and things, for example:

if (deposit/price) < 0.2
    return price*0.05;

Using NSDecimalNumber makes this a lot more difficult. As far as I'm aware I should be converting any magic numbers (in this case 0.2 and 0.05) to NSDecimalNumber so then I can compare them and use functions such as NSDecimalMultiply.

Also, if I have a function that is something like:

return (minRandomPercentage + ((maxRandomPercentage - minRandomPercentage) * (randomNumber)

it ends up becoming this ridiculous string of nested function calls like:

return [minRandomPercentage decimalNumberByAdding:[[maxRandomPercentage decimalNumberBySubtracting:  minRandomPercentage] decimalNumberByMultiplyingBy:random]]

Is this seriously how objective-c deals with decimals? Can anyone give me any clues on how to make this a lot less arduous? I can live with the nested function calls if I could do comparisons with the result and not have to be casting every magic number I have.

like image 613
dnatoli Avatar asked Apr 01 '11 02:04

dnatoli


People also ask

What is NSDecimalNumber?

NSDecimalNumber , an immutable subclass of NSNumber , provides an object-oriented wrapper for doing base-10 arithmetic. An instance can represent any number that can be expressed as mantissa x 10^exponent where mantissa is a decimal integer up to 38 digits long, and exponent is an integer from –128 through 127.

What is NSNumber in Swift?

NSNumber is a subclass of NSValue that offers a value as any C scalar (numeric) type. It defines a set of methods specifically for setting and accessing the value as a signed or unsigned char , short int , int , long int , long long int , float , or double or as a BOOL .


1 Answers

If you can't afford to deal with the rounding errors that can occur with the standard base-2 floating point types, you'll have to use NSDecimal or NSDecimalNumber. NSDecimal is a C struct, and Foundation provides a C interface for dealing with it. It provides functions NSDecimalAdd, NSDecimalMultiply, etc.

From the Number and Value Programming Guide: You might consider the C interface if you don’t need to treat decimal numbers as objects—that is, if you don’t need to store them in an object-oriented collection like an instance of NSArray or NSDictionary. You might also consider the C interface if you need maximum efficiency. The C interface is faster and uses less memory than the NSDecimalNumber class.

If you're writing object-oriented code, and you're not interacting with massive data sets, it might be best to stick with NSDecimalNumber. If you profile your code and find that using NSDecimalNumber is causing a high memory overhead, then you may need to consider alternatives.

If rounding errors are not a concern, you can also use native C scalars. See: How to add two NSNumber objects?

NSNumber and NSDecimalNumber are used as object wrappers when you need to pass a number to a method or store numbers in a collection. Since NSArray, NSSet, NSDictionary, etc. only allow you to store objects of type 'id', you can't store ints, floats, etc. natively.

If you're dealing with large data sets and can afford rounding errors, you can use ints, floats, doubles, etc. raw. Then when you have your result and you need to store it or pass it to another object, you can wrap it up in an NSNumber accordingly.

If you do have a need to store large collections of numbers, it's much more efficient to use C arrays than to initialize and store lots of NSNumber objects.

like image 151
Stephen Poletto Avatar answered Sep 30 '22 23:09

Stephen Poletto