2

Why does the following code produce "numberFromString = 9.390000000000001" rather than "numberFromString = 9.39"?

NSNumberFormatter *numFormatter = [[NSNumberFormatter alloc] init];
[numFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
[numFormatter setPositiveFormat:@"$##0.00"];
[numFormatter setNegativeFormat:@"-$##0.00"];
NSNumber *nTCA = [numFormatter numberFromString:@"$9.39"];

NSLog(@"numberFromString = %@", nTCA);

I get the above results on OS X 10.6 and iOS 4.3.3.

What's the best way to correct this error?

Thanks

Rob Wright
  • 3,374
  • 2
  • 18
  • 12

1 Answers1

4

I suspect you are running into an error as a result of using floating-point precision. The way to fix this is to use NSDecimalNumber instead of NSNumber. There's a great post about this here.

NSDecimalNumber has a + decimalNumberWithString: method. Would that suffice for your purposes?

Nate Thorn
  • 2,193
  • 2
  • 23
  • 27
  • The only problem with that article is that the author forgets that `NSDecimalNumber` is a subclass of `NSNumber` and so responds to things like `+numberWithInt:` and `+numberWithDouble:` You don't need to use `+decimalNumberWithMantissa:exponent:isNegative:` to create them from primitives. – JeremyP Jun 21 '11 at 10:23
  • @JeremyP Actually, since `+numberWithInt:` and `+numberWithDouble:` and the like return an `NSNumber*`, I'm pretty sure you can't use them to create `NSDecimalNumber*`. See this SO question: http://stackoverflow.com/questions/453691/how-use-nsdecimalnumber – Nate Thorn Jun 21 '11 at 11:22
  • @Nate Thorn: `[NSDecimalNumber numberWithInt: x]` will give you an `NSDecimalNumber` – JeremyP Jun 21 '11 at 11:33
  • @Nate Thorn: And even if it doesn't, the equivalent `-initWith...` methods definitely should. – JeremyP Jun 21 '11 at 11:41
  • @JeremyP Well, it looks like it's a question of API. The API states that the `+numberWithInt:` methods return an `NSNumber*` (unspecialized) so *technically* you can't assume that they'll be `NSDecimalNumber*`s. That being said, I just ran a quick test and it looks like they definitely are returning `NSDecimalNumber*`s. So in the end, I guess it comes down to a question of philosophy. Do you blindly follow the API to the letter, or do you just cast the darn thing and get on with life? :) – Nate Thorn Jun 21 '11 at 12:20
  • @Nate Thorn: I also tried the same test and got an NSDecimalNumber back. However, on reflection, I think I would agree with you and stick with the `-initWith...` methods just for safety. I just looked up the `+array` method of NSArray, which can be sent to `NSMutableArray` to get a mutable array and its return type is id (and it also explicitly says it is used by subclasses in the documentation). – JeremyP Jun 21 '11 at 13:49