6

我在使用 NSNumberFormatter 在 ObjC 中格式化非常大的数字时遇到了意外行为。

无论小数位数如何,数字格式化程序似乎都会在第十五位数之后舍入小数(NSDecimalNumber)。

以下测试在值 1,3 和 5 上失败。

两个请求:

  • 任何关于替代代码的建议将不胜感激?
  • 我认为问题是由于在 NSNumberFormatter 中使用了硬编码的数字限制而发生的?

如果出现问题,此处的帖子列出了没有足够描述的解决方法。此外,我们的应用程序(银行业)在多个国家/地区运行,我们将格式链接到后端配置的用户区域设置。这种解决方法意味着我们编写自己的数字格式化程序来处理要求。我不想做的事情。

- (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);
}
4

3 回答 3

4

不幸的是,NSNumberFormatter不能与NSDecimalNumber. 问题(很可能)是它做的第一件事就是调用doubleValue它想要格式化的数字。

另请参阅NSDecimalNumber 舍入长数字

经过多次尝试NSNumberFormatter,我创建了自己的格式化程序,实际上非常简单:

  1. 处理NaN
  2. 圆形使用roundToScale:
  3. 得到stringValue
  4. 检查是否为负,删除前导-
  5. 查找小数点 ( .)
  6. 本地化小数点 ( [locale objectForKey:NSLocaleDecimalSeparator])
  7. 添加分组分隔符 ( [locale objectForKey:NSLocaleGroupingSeparator])
  8. 如果为负数,则在格式化货币时添加前导-或将数字放入括号中。
  9. 完毕。
于 2012-12-19T13:36:18.250 回答
1

你应该从这个开源代码编译你自己的 NSNumberFormatter,改变前缀。这应该允许您调试格式并了解发生这种情况的原因。在最坏的情况下,您可以向 Apple 提交补丁。

http://code.google.com/p/cocotron/source/browse/Foundation/NSNumberFormatter.m?r=7542c3a7ef0ef75479e6154a75d304113f5a9738

于 2012-12-19T13:29:36.193 回答
1

你已经设置maximumFractionDigits为两个。所有失败的测试在预期值中都有三个小数位。期望或代码都需要更改以匹配。如果我进行此更改:

formatter.maximumFractionDigits = 3;

然后满足您的所有测试用例。

于 2012-12-19T13:29:39.017 回答