You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复NSString转NSDecimalNumber的decimalNumberWithString转换异常?

NSString转NSDecimalNumber的精度偏差问题

测试代码

NSLog(@"calcuMax_test - calculateMaxForCross feeRateDecimal: --------------------------------------------------------------------");
NSLog(@"calcuMax_test - calculateMaxForCross feeRateDecimal: %@",[NSDecimalNumber decimalNumberWithString:@"0.0001"]);
NSLog(@"calcuMax_test - calculateMaxForCross feeRateDecimal: %@",[NSDecimalNumber decimalNumberWithString:@"0.0002"]);
NSLog(@"calcuMax_test - calculateMaxForCross feeRateDecimal: %@",[NSDecimalNumber decimalNumberWithString:@"0.0003"]);
NSLog(@"calcuMax_test - calculateMaxForCross feeRateDecimal: %@",[NSDecimalNumber decimalNumberWithString:@"0.0004"]);
NSLog(@"calcuMax_test - calculateMaxForCross feeRateDecimal: %@",[NSDecimalNumber decimalNumberWithString:@"0.0005"]);
NSLog(@"calcuMax_test - calculateMaxForCross feeRateDecimal: %@",[NSDecimalNumber decimalNumberWithString:@"0.0006"]);
NSLog(@"calcuMax_test - calculateMaxForCross feeRateDecimal: %@",[NSDecimalNumber decimalNumberWithString:@"0.0007"]);
NSLog(@"calcuMax_test - calculateMaxForCross feeRateDecimal: %@",[NSDecimalNumber decimalNumberWithString:@"0.0008"]);
NSLog(@"calcuMax_test - calculateMaxForCross feeRateDecimal: %@",[NSDecimalNumber decimalNumberWithString:@"0.0009"]);
NSLog(@"calcuMax_test - calculateMaxForCross feeRateDecimal: %@",[NSDecimalNumber decimalNumberWithString:@"0.001"]);
NSLog(@"calcuMax_test - calculateMaxForCross feeRateDecimal: %@",[NSDecimalNumber decimalNumberWithString:@"0.002"]);
NSLog(@"calcuMax_test - calculateMaxForCross feeRateDecimal: %@",[NSDecimalNumber decimalNumberWithString:@"0.003"]);
NSLog(@"calcuMax_test - calculateMaxForCross feeRateDecimal: %@",[NSDecimalNumber decimalNumberWithString:@"0.004"]);
NSLog(@"calcuMax_test - calculateMaxForCross feeRateDecimal: %@",[NSDecimalNumber decimalNumberWithString:@"0.005"]);
NSLog(@"calcuMax_test - calculateMaxForCross feeRateDecimal: %@",[NSDecimalNumber decimalNumberWithString:@"0.006"]);
NSLog(@"calcuMax_test - calculateMaxForCross feeRateDecimal: %@",[NSDecimalNumber decimalNumberWithString:@"0.007"]);
NSLog(@"calcuMax_test - calculateMaxForCross feeRateDecimal: %@",[NSDecimalNumber decimalNumberWithString:@"0.008"]);
NSLog(@"calcuMax_test - calculateMaxForCross feeRateDecimal: %@",[NSDecimalNumber decimalNumberWithString:@"0.009"]);
NSLog(@"calcuMax_test - calculateMaxForCross feeRateDecimal: --------------------------------------------------------------------");

输出结果

calcuMax_test - calculateMaxForCross feeRateDecimal: --------------------------------------------------------------------
calcuMax_test - calculateMaxForCross feeRateDecimal: 0.0001
calcuMax_test - calculateMaxForCross feeRateDecimal: 0.0002
calcuMax_test - calculateMaxForCross feeRateDecimal: 0.0003
calcuMax_test - calculateMaxForCross feeRateDecimal: 0.0004
calcuMax_test - calculateMaxForCross feeRateDecimal: 0.0005
calcuMax_test - calculateMaxForCross feeRateDecimal: 0.0006000000000000001
calcuMax_test - calculateMaxForCross feeRateDecimal: 0.0006999999999999999
calcuMax_test - calculateMaxForCross feeRateDecimal: 0.0008
calcuMax_test - calculateMaxForCross feeRateDecimal: 0.0009
calcuMax_test - calculateMaxForCross feeRateDecimal: 0.001
calcuMax_test - calculateMaxForCross feeRateDecimal: 0.002
calcuMax_test - calculateMaxForCross feeRateDecimal: 0.003
calcuMax_test - calculateMaxForCross feeRateDecimal: 0.004
calcuMax_test - calculateMaxForCross feeRateDecimal: 0.005
calcuMax_test - calculateMaxForCross feeRateDecimal: 0.006
calcuMax_test - calculateMaxForCross feeRateDecimal: 0.006999999999999999
calcuMax_test - calculateMaxForCross feeRateDecimal: 0.008
calcuMax_test - calculateMaxForCross feeRateDecimal: 0.008999999999999999
calcuMax_test - calculateMaxForCross feeRateDecimal: --------------------------------------------------------------------

问题

为何转换结果出现精度偏差?正确的转换方法是什么?


解答

精度偏差的原因

NSDecimalNumber本身是十进制精确浮点类型,转换@"0.0006"这类字符串时内部存储的值是完全精确的。你看到的精度偏差只是打印显示的问题:当用%@输出NSDecimalNumber时,系统会先把它转换成double类型,而double是二进制浮点类型,无法精确表示所有十进制小数(比如0.0006),所以输出时会出现近似值。

正确的处理方法

1. 用NSNumberFormatter格式化输出

如果只是要正确显示数值,使用NSNumberFormatter来指定小数位数和格式,避免自动转double带来的偏差:

NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
formatter.numberStyle = NSNumberFormatterDecimalStyle;
formatter.minimumFractionDigits = 4;
formatter.maximumFractionDigits = 4;
formatter.roundingMode = NSNumberFormatterRoundHalfUp;

NSDecimalNumber *num = [NSDecimalNumber decimalNumberWithString:@"0.0006"];
NSLog(@"Formatted number: %@", [formatter stringFromNumber:num]);

输出会是0.0006,完全符合预期。

2. 直接用NSDecimalNumber做精确运算

如果需要进行计算,直接使用NSDecimalNumber提供的API(比如decimalNumberByAdding:、decimalNumberByMultiplyingBy:等),这些运算都是基于十进制的精确计算,不会有二进制浮点的精度问题。


内容的提问来源于stack exchange,提问作者won

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 09:37:04