Operations on NSDecimalNumbers in iOS

Calculations carried out on NSDecimalNumbers are handy especially when we need the highest accuracy, for example, when holding currency operations.

Maciej Gomółka
EL Passion Blog
4 min readAug 11, 2017

--

Question: What is the result of 1.2–1.0 substraction?

Human: That’s easy! It’s 0.2

Computer: The correct outcome is: 0.2000000477

It appears that for computers such operation is not so obvious as it is for humans (assuming that you will mistakenly use Float type).

If you’re curious why such discrepency appears and want to know how to avoid these kind of mistakes, this article is definitely for you!

What’s NSDecimalNumber?

As stated in Apple’s documentation it can be defined as:

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.

To sum up we deal with two integers. The first one defines a given number transcribed without a comma (mantista). The second on the other hand, determines the place of the comma (exponent).

Having this in mind NSDecimalNumber is understood as a number which can be represented as follows:

This kind of transcription solves the problem of floating point numbers depiction in the binary system.

MGDecimalOperations

MGDecimalOperation is a library which enables us to conduct basic operations on NSDecimalNumbers. What pushed me to create it was the lack of transparency in the transcript of operations on NSDecimalNumber in Objective-C.

Exemplary calculation:

It’s counterpart conducted on NSDecimalNuber:

with MGDecimalOperations library:

What makes the operation conducted by MGDecimalNumbers more legible is the fact that it immediately enables us to see the process itself.
What’s more we don’t have to bother ourselves about neither the sequence of conducted operations nor brakets. The only thing we have to do is to feed the dictionary of variables and operation which we want to perform in String. Then pass a reference to the NSError object which includes information about obstruction that may occur during validation of data.

You can find the library at CocoaPods.org or click here.

What’s the deal with floating point numbers?

The most common problem that all of us propably encounter is their representation in the binary system. We can’t put the numbers in a sum of the power of 2 which makes it impossible to write some of them (for example: 0.1 or 0.2). The outputs that we receive are quite good approximations, however, they aren’t the exact representations (of those numbers) at all.

As enclosed example shows, it’s impossible for us to get the exact representation of 0.1. The only thing we can get is it’s an approximation dependent on the amount of bits in which a given numer is saved.

Having performed 100000 times the addition of number 0.00001 (expected outcome: 1) to: Float, Double or NSDecimalNumber we receive following results:

Float — 1.00099, Double — 0.999999999998084, NSDecimalNumber — 1

It shows us what kind of errors we may expect while performing more operations on various kinds of floating point numbers.

It’s easy to spot that the approximation of Double is way more precise than the approximation of Float. But why is that? It’s certainly connected to the fact that the Float Number is saved on smaller amount of bits than the Double one.

The winner of this competition, however, is NSDecimalNumber which has given us the most precise result.

Where is it applied?

Calculations carried out on NSDecimalNumber are handy especially when we need the highest accuracy, for example, when holding currency operations. This is because errors resulting from imprecise binary representation, which occur only after making many calculations, can introduce significant margins between received and real value.

If the precision in our calculations is not that crucial, we’re free to abandon NSDecimalNumber, because conducting an operation on it entails entering a great deal of both redundant and illegible code. Additionally, such calculations in comparison to primitive types take more space and time.

Tap the ❤ button if you found this article useful!

About the Author
Maciej is iOS Developer at EL Passion. You can find him on Facebook or LinkedIn.

Find EL Passion on Facebook, Twitter and Instagram.

--

--