使用NSNumberFormatter的.floor roundingMode时,Float与Double计算结果不一致的原因咨询
为啥Float和Double用NumberFormatter.floor会得到不同结果?
嘿,这个问题的根源其实藏在二进制浮点数的精度特性里,咱们一步步理清楚:
1. 浮点数的近似存储问题
十进制里的3.6,在二进制浮点数体系里是没法精确表示的——就像咱们没法用分数精确表示1/3一样。Float(单精度32位)和Double(双精度64位)的存储精度不同,导致它们对36/10的计算结果存储了不同的近似值:
Float(36)/Float(10)的实际值是3.5999999046325684,一个略小于3.6的数,误差相对明显。Double(36)/Double(10)的实际值是3.5999999999999996,同样略小于3.6,但误差极小,小到直接打印时Swift都会把它显示成3.6。
2. .floor roundingMode的作用
.floor是向下取整,也就是取不大于原数的最大数值(这里是保留两位小数):
- 对于Float的近似值(3.5999999...),它比3.6小一丢丢,向下取两位小数时就会被取成3.59。
- 对于Double的近似值(3.5999999999999996...),因为误差实在太小,NumberFormatter在处理时会把它视为足够接近3.6,向下取整到两位小数就得到了3.60。
3. 怎么避免这种差异?
如果需要精确的十进制计算,建议用Decimal类型代替Float/Double,它专门为十进制数设计,不会有二进制浮点数的精度问题:
let formatter = NumberFormatter() formatter.numberStyle = .decimal formatter.usesGroupingSeparator = false formatter.roundingMode = .floor formatter.minimumFractionDigits = 2 formatter.maximumFractionDigits = 2 let v = 36 let scale = 10 let decimalValue = Decimal(v) / Decimal(scale) let result = formatter.string(from: decimalValue as NSNumber)! print(result) // 输出 3.60
内容的提问来源于stack exchange,提问作者Giorgio
相关产品推荐
相关产品推荐

