为何Float类型存储9138497.986时会出现精度丢失?
核心原因很简单:Float是32位单精度浮点数,最多只能精确保留6-7位十进制有效数字,而你输入的9138497.986有8位有效数字,超出了它的精度上限,只能被舍入到最接近的可表示值。
具体细节拆解
Float的存储限制
Float用32位空间存储数字:1位管正负,8位管数值量级,剩下23位管具体的数字细节(加上隐含的1位,总共24位有效二进制位)。换算成十进制的话,24位二进制大概对应7.2位有效数字,也就是说,超过7位的部分,Float没法精准记录,只能做近似处理。9138497.986的存储过程
9138497.986转成二进制后,没法用24位的细节位完全表示,所以会自动舍入到最近的、Float能存储的数值——这个数值就是9138498.0,因此格式化输出三位小数时就显示成了9138498.000。除以10后能显示小数的原因
把9138497.986除以10得到913849.7986,这个数只有7位有效数字,刚好在Float的精度范围内,所以能存储一个接近的近似值,格式化后显示的913849.812就是这个近似值的表现,和原始值的差异是浮点数舍入的正常现象。Double没问题的原因
Double是64位双精度浮点数,能保留约16位十进制有效数字,远大于9138497.986的8位,所以可以精准存储这个数的近似值,格式化后就能显示出原始的三位小数9138497.986。SCNVector3的表现
SCNVector3内部使用的是Float类型,所以初始化时传入的9138497.986会被转换成Float的近似值9138498;而216877.354、2878.604的有效数字在Float的精度范围内,所以舍入后的结果更接近原始值。
验证代码
你可以通过以下代码直接查看Float的实际存储值:
let f1 = Float(9138497.986) print(f1) // 直接输出 9138498.0
内容的提问来源于stack exchange,提问作者tospig

