iOS 11中NSDecimalNumber舍入功能失效问题求助
解决iOS版本间浮点数舍入结果不一致的问题
这个问题本质上是二进制浮点数的精度局限性加上不同iOS版本下Foundation框架舍入实现的细微差异导致的。你遇到的67.95999999999997这个值,本身就是67.96在二进制浮点数中的近似表示——因为十进制的0.96无法被二进制浮点数精确存储,所以会有微小的误差。而iOS 9和iOS 11对这种近似值的舍入处理逻辑有微调,才出现了结果差异。
下面给你两个可靠的解决方案,能在所有iOS版本下得到一致的舍入结果:
方案1:使用NSDecimalNumber进行精确十进制运算
NSDecimalNumber是专门为精确处理十进制数值设计的,完全避免二进制浮点数的精度问题。示例代码如下:
// 建议用字符串初始化,从根源避免浮点数精度损失 NSDecimalNumber *myNumber = [NSDecimalNumber decimalNumberWithString:@"67.95999999999997"]; // 设置舍入规则:保留2位小数,四舍五入 NSDecimalNumberHandler *roundingHandler = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain scale:2 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO]; NSDecimalNumber *roundedNumber = [myNumber decimalNumberByRoundingAccordingToBehavior:roundingHandler]; NSLog(@"%@", roundedNumber); // 输出:67.96
如果你的原始值是double类型,也可以先转换成字符串再初始化NSDecimalNumber,避免精度丢失。
方案2:使用NumberFormatter指定明确的舍入模式
如果你更习惯用格式化输出的方式,NumberFormatter可以让你明确指定舍入规则,确保跨版本一致:
double myNumber = 67.95999999999997; NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; formatter.numberStyle = NSNumberFormatterDecimalStyle; formatter.maximumFractionDigits = 2; formatter.roundingMode = NSNumberFormatterRoundHalfUp; // 四舍五入模式 NSString *roundedString = [formatter stringFromNumber:@(myNumber)]; NSLog(@"%@", roundedString); // 输出:67.96
为什么原来的方法会出问题?
直接对double类型的数值做舍入操作时,依赖的是系统底层的浮点数处理逻辑。iOS 11可能调整了舍入算法的细节,导致对这种接近临界值的近似浮点数处理结果和iOS 9不同。而上面两种方法都是基于十进制的精确处理,不会受系统版本的这种微调影响。
内容的提问来源于stack exchange,提问作者Mark Biondi
相关产品推荐
相关产品推荐

