I am running into unexpected behaviour formatting very large numbers in ObjC using the NSNumberFormatter.
It seems that the number formatter rounds decimals (NSDecimalNumber) after the fifteenth digit regardless of fraction digits.
The below test fails on values 1,3 and 5.
Two requests:
The post here lists a workaround without sufficient description if the problem. Also our application (banking sector) runs across multiple countries and we link the formatting to the user's locale as configured in the backend. This workaround would imply that we write our own number formatter to handle the requirement. Something I do not want to do.
- (void)testFormatterUsingOnlySDK {
NSDecimalNumber *value1 = [NSDecimalNumber decimalNumberWithMantissa: 9423372036854775808u exponent:-3 isNegative:YES];
NSDecimalNumber *value2 = [NSDecimalNumber decimalNumberWithMantissa: 9999999999999990u exponent:-3 isNegative:YES];
NSDecimalNumber *value3 = [NSDecimalNumber decimalNumberWithMantissa: 9999999999999991u exponent:-3 isNegative:YES];
NSDecimalNumber *value4 = [NSDecimalNumber decimalNumberWithMantissa: 99999999999999900u exponent:-4 isNegative:YES];
NSDecimalNumber *value5 = [NSDecimalNumber decimalNumberWithMantissa: 11111111111111110u exponent:-4 isNegative:YES];
NSNumberFormatter *formatter = [[[NSNumberFormatter alloc] init] autorelease];
formatter.allowsFloats = YES;
formatter.maximumFractionDigits = 3;
[self assertStringAreEqualWithActual:[formatter stringFromNumber:value1] andExpeted: @"-9423372036854775.808"];
[self assertStringAreEqualWithActual:[formatter stringFromNumber:value2] andExpeted: @"-9999999999999.99"];
[self assertStringAreEqualWithActual:[formatter stringFromNumber:value3] andExpeted: @"-9999999999999.991"];
[self assertStringAreEqualWithActual:[formatter stringFromNumber:value4] andExpeted: @"-9999999999999.99"];
[self assertStringAreEqualWithActual:[formatter stringFromNumber:value5] andExpeted: @"-1111111111111.111"];
}
- (void)assertStringAreEqualWithActual:(NSString *)actual andExpeted:(NSString *)expected {
STAssertTrue([expected isEqualToString:actual], @"Expected %@ but got %@", expected, actual);
}
Unfortunately, NSNumberFormatter
doesn't work correctly with NSDecimalNumber
.
The problem (very probably) is that the first thing it does is calling doubleValue
on the number it wants to format.
See also NSDecimalNumber round long numbers
After many tries with NSNumberFormatter
, I have created my own formatter, it's actually very easy:
NaN
.roundToScale:
stringValue
-
.
)[locale objectForKey:NSLocaleDecimalSeparator]
)[locale objectForKey:NSLocaleGroupingSeparator]
)-
or put the number into parenthesis if you are formatting currency.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With