Question

I have defined price in my CoreData object LineItem to be a double, however, to set or use the value of price, I can only use the NSNumber wrapper, which is how CoreData works and it's just fine.

But I have discovered accuracy issues when setting the numbers.

For example, I have got a double from a UITextField numeric input:

[self.lineItem setPriceValue:round([_finalPrice doubleValue]*100)/100]; // This actually trivial since it is already 83.99 as you see in the log but doesn't affect the result.

NSLog(@"Price to set: %@", _finalPrice);
NSLog(@"Price set: %@", [self.lineItem price]);

Here is the log:

2014-03-30 21:03:24.207 MyApp[20998:60b] Price to set: 83.99
2014-03-30 21:03:24.207 MyApp[20998:60b] Price set: 83.98999999999999

This looks like one of those decimal glitches, except for the fact that I haven't really used decimal anywhere. There are possibilities that RestKit have used it somewhere, which is out of my control, but I doubt it.

Meanwhile it is causing problem in my app since it is a business app and the API that I talk to would just read 83.98999999999999 as 83.98, causing a cent or two off in every transaction involving those problematic numbers.

Was it helpful?

Solution

The floating point types float and double store numbers in binary and not all decimal fractions have an exact binary fraction equivalent. For this reason currency calculations, which need to be precise, should either be done using integer types using an appropriate unit, e.g cents or pennies, or with decimal floating point types, such as are provided by NSDecimalNumber. The choice on which to use depends on the range of values you need to represent and the type of calculations you need to perform.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top