- Storing Numbers in Collections
- Performing Decimal Arithmetic
- Converting Between Strings and Numbers
- Reading Numbers from Strings
Performing Decimal Arithmetic
From: decimal.m
6NSDecimalNumber *one =
7[NSDecimalNumber one];
8NSDecimalNumber *fortyTwo =
9[NSDecimalNumber decimalNumberWithString: @"42"
];
10NSDecimalNumber *sum =
11[one decimalNumberByAdding: fortyTwo];
12NSDecimal accumulator = [sum decimalValue];
13NSDecimal temp = [fortyTwo decimalValue];
14NSDecimalMultiply(&accumulator, &accumulator, &
temp, NSRoundPlain);
15temp = [one decimalValue];
16NSDecimalAdd(&accumulator, &accumulator, &temp,
NSRoundPlain);
17NSDecimalNumber *result =
18[NSDecimalNumber decimalNumberWithDecimal:
accumulator];
C gives you two options for working with numbers: integers and floating-point values. Floating-point values are made of two components: a mantissa and an exponent. Their value is two to the power of the exponent, multiplied by the mantissa.
The problem with floating-point values is that they are binary. This means that their precision is defined in terms of binary digits, which is not always what you want. For a financial application, for example, you may need to store amounts to exactly four decimal places. This is not possible with floating-point values; a value such as 0.1 cannot be represented by any finite binary floating-point, just as 0.1 in base three (one third) cannot be represented by any finite decimal sequence.
A binary number is the sum of a set of powers of two, just as a decimal number is a sum of powers of ten. With fractional values, the digits after the radix point indicate halves, quarters, eighths, and so on. If you try to create a value of 0.1 by adding powers of two, you never succeed, although you get progressively closer. Exactly the same thing happens when you try to create a third by adding powers of ten (a three tenths, plus three hundredths, plus three thousands, and so on).
One solution is to use fixed-point arithmetic. Rather than storing dollars, you might store hundredths of a cent. You must then remember to normalize your values, and you are limited by the range of an integer type. Objective-C provides another option: decimal floating-point types.
The NSDecimal type is a C structure that represents a decimal value. Somewhat strangely, there is no C API for creating these. You must create an NSDecimalNumber instance and then send it a -decimalValue message.
You then have two choices for arithmetic. NSDecimalNumber instances are immutable. You can create new ones as a result of arithmetic—for example, by sending a decimalNumberByAdding: message to one.
Alternatively, you can use the C API, which modifies the value of the structure directly.
If you are just performing one arithmetic operation and then storing the result in an object, the first option is simpler. If you are doing a number of steps then it is faster to use the C APIs. Because these modify the structure, they do not require you to create a new object for each intermediate step.
Neither of these is especially fast. The decimal number is represented as an array of digits, and these are operated on in pairs, after the two numbers have been normalized. You can expect to get similar performance to a software floating-point implementation—possibly slightly worse as NSDecimal is not widely used and therefore has not been the focus of much optimization effort.
NSDecimalNumber is a subclass of NSNumber, so all of the ways of converting NSNumbers to strings that we'll look at in the next section work as expected. You can also convert them to C primitive types using the standard methods for accessing these on number objects, but these methods may truncate or approximate the decimal value.