Reputation: 2490
It started quite normally. I'm writing complex calculation application for iPhone. I decided to use float primitive for representing numbers. So, time came to start rounding and formatting output, but first of all rounding. I want to round numbers to different number of decimal places. FOund out there is no useful C function. OK, so I can write my own. But then I have numbers from application settings to persist. I found out only objects can be persisted. So I started to dig in NSNumber and NSDecimalNumber. Especially the latter gives me shivers only when look at it. Delegate needed to implement roundings, no smiple arithmetic operators, special methods instead....:( What is left then of pure C simplicity?
Is there any other way to simplify this?
Upvotes: 1
Views: 919
Reputation: 43472
You could probably use theValue - fmod(theValue, 0.01)
to round to, for this example, the nearest 0.01.) But be warned!
Computers don't actually work with decimal numbers--i.e. numbers in base ten, the way we use them in normal life. They work with binary numbers, and that includes floating-point numbers. They're represented in binary as well, and that means that "number of decimal places" is not always a meaningful property of a floating-point number.
For instance, a floating-point number cannot exactly represent 0.1, and you'll get something like 0.1000000001 if you try to use it in your code. The exact value you get varies by implementation, and is not correctable by subtracting the difference, as the computer can't tell that there is a difference--that's as close as it can get to 0.1.
This is why classes like NSDecimalNumber
exist. They simulate decimal mathematics to give values that seem more sane to us. They're prone to many of the same problems as floating-point, but with different values (1.0 / 3.0 is not exactly representable in decimal, for instance, but it's still a discrete value.)
So yes, if your numbers must be rounded to a particular number of decimal places, you need to use NSDecimalNumber
for most decimal operations. If it's just for display, you can use something like NSNumberFormatter
instead to get the display value without modifying the number itself in memory.
The second part of your question--storing numeric values in user defaults, is easily solved. NSNumber
"wraps" a primitive numeric type, but it can be unwrapped:
NSNumber *n = [NSNumber numberWithDouble: 1.234567890];
double aDouble = [n doubleValue];
Upvotes: 3
Reputation: 21464
Use NSDecimal
and NSDecimalNumber
whenever you need exact accuracy, especially for any accounting/financial stuff. For anything else that requires accuracy, but for which you don't need exact precision, use a double
, not a float
. NSNumber
is simply an Obj-C object wrapper for number primitives.
For formatting and rounding, look at NSNumberFormatter
. Any C primitive number can be wrapped up into an NSNumber
, then you can use an NSNumberFormatter
to convert it into an NSString
. It might seem somewhat clumsy at first, but in real world use, it works pretty well, since you get a very high level of formatting control.
Upvotes: 2