Swift中1.005四舍五入至两位小数结果异常问题及解决方法
嘿,这个问题其实是浮点数精度误差搞的鬼!你遇到的情况特别典型,咱们一步步拆解来看:
为什么会出现这个问题?
Double类型是基于二进制的浮点数,它没办法精确表示所有十进制小数。比如你用到的1.005,在二进制里是一个无限循环的近似值,实际存储的数值其实是略小于1.005的(大概是1.0049999999999998...)。当你执行value * 100时,这个近似值乘以100后就变成了100.49999999999998...,再用round()函数处理,自然就会向下取整到100,最后除以100.0就得到了1.0,而非预期的1.01。
至于测试代码里其他数字(比如2.005)能得到正确结果,是因为它们的二进制近似值刚好略大于实际的十进制数,乘以100后会超过200.5,round()就会向上取整。
靠谱的解决方案
1. 使用Decimal类型处理精确十进制计算
Decimal是专门为十进制小数设计的类型,能从根源上避免二进制浮点数的精度问题。示例代码:
for i in 1..<11 { let value = Decimal(i) + Decimal(string: "0.005")! let roundedValue = (value * 100).rounded() / 100 print("\(value) -> \(roundedValue)") }
运行这段代码,所有数值都会正确保留两位小数,1.005会得到1.01。
2. 使用NumberFormatter格式化输出(适合UI展示)
如果你的需求只是把数值格式化为字符串展示给用户,直接用NumberFormatter更简单,它内部会自动处理精度问题:
let formatter = NumberFormatter() formatter.numberStyle = .decimal formatter.minimumFractionDigits = 2 formatter.maximumFractionDigits = 2 formatter.roundingMode = .halfUp for i in 1..<11 { let value = Double(i) + 0.005 if let formattedString = formatter.string(from: NSNumber(value: value)) { print("\(value) -> \(formattedString)") } }
这个方法输出的字符串会是你预期的"1.01"、"2.01"等格式,非常适合界面展示场景。
3. 手动添加极小偏移量(不推荐,慎用)
如果不想切换类型,也可以尝试给原数值加一个极小的偏移量(比如1e-8)来抵消精度误差:
for i in 1..<11 { let value = Double(i) + 0.005 let offsetValue = value + 1e-8 let roundedValue = round(offsetValue * 100) / 100.0 print("\(value) -> \(roundedValue)") }
不过这个方法不够可靠,不同数值可能需要不同的偏移量,极端场景下可能会引入新的错误,所以只建议临时应急使用。
总结
优先推荐用Decimal做精确的十进制计算,或者用NumberFormatter做格式化展示,这两种方法都能彻底解决浮点数精度导致的四舍五入错误。
内容的提问来源于stack exchange,提问作者behruzinho

