Reputation: 1411
I'm having a serious dispute with NSNumberFormatter, and even after going through its extensive documentation, I haven't quite been able to wrap my head around a pretty straightforward issue that I encountered. I hope you guys can help me out.
What I have: an NSDecimalNumber
representing a calculation result, displayed in a UITextField
What I need: Scientific notation of that result.
What I'm doing:
-(void)setScientificNotationForTextField:(UITextField*)tf Text:(NSString*)text {
NSString* textBefore = text;
// use scientific notation, i.e. NSNumberFormatterScientificStyle
NSNumberFormatter* formatter = [[NSNumberFormatter alloc] init];
//[formatter setGeneratesDecimalNumbers:YES];
[formatter setNumberStyle:NSNumberFormatterScientificStyle];
NSDecimalNumber* number = (NSDecimalNumber*)[formatter numberFromString:text];
tf.text = [number descriptionWithLocale:[[Utilities sharedUtilities] USLocale]];
NSString* textAfter = tf.text;
// DEBUG
NSLog(@"setScientificNotation | text before = %@, text after = %@", textBefore, textAfter);
[formatter release];
}
What happens:
A certain result may be 0.0099. textBefore
will hold that correct value. If I don't tell the formatter to generate decimal numbers (commented out in the above snippet), it will create an NSNumber from an NSDecimalNumber which creates a false result and turns textAfter
into 0.009900000000000001 - a rounding error due to the reduced precision of NSNumber over NSDecimalNumber.
If I do tell the NumberFormatter to generate decimals, it will still create the wrong result . And what's more, where before it would insert the exponent notation (e.g. "1.23456e-10"), it would now generate (and thus display) the full decimal number, which is not what I want.
Again, I'd like to have the formatter use NSDecimalNumber so it doesn't falsify results plus have exponent notation where necessary.
Am I using the class wrong? Did I misinterpret the documentation? Can someone explain why this happens and how I can create the behavior I want? I will of course continue researching and update if I find anything.
Upvotes: 1
Views: 2638
Reputation: 43852
You can't just cast an NSNumber
to an NSDecimalNumber
and expect it to work. If your number is not too complex, you can ditch NSNumberFormatter
and try using this instead:
NSDecimalNumber* number = [NSDecimalNumber decimalNumberWithString:text];
That will give you an actual NSDecimalNumber
instance, with its precision.
Unfortunately, setGeneratesDecimalNumbers:
doesn't work properly. It's a known bug.
If your number is too complex to work with decimalNumberWithString:
, you're probably out of luck with Apple's APIs. Your only options are either parsing the string manually into something NSDecimalNumber
can understand or performing some post-processing on the imprecise value given to you by NSNumberFormatter
.
Finally, if you really want a number in scientific notation, why not just use the number formatter you just used? Just call stringFromNumber:
to get the formatted value.
Upvotes: 4