Scala中Double类型简单乘法出现精度异常,是否为框架问题?
别慌,这既不是Scala的bug,也不是你操作错了——这是二进制浮点数的精度特性导致的常见问题,不止Scala,Java、Python这类使用标准浮点数类型的语言都会遇到这种情况。
先还原你遇到的现象:
scala $ Welcome to Scala 2.12.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_111).
Type in expressions for evaluation. Or try :help.
scala> val radius:Double = 10.2
radius: Double = 10.2
scala> radius * 10
res0: Double = 102.0
scala> radius * 100
res1: Double = 1019.9999999999999
scala> radius * 1000
res2: Double = 10200.0
问题出在哪?
我们日常用的十进制小数10.2,转换成二进制是一个无限循环的小数(就像十进制里1/3永远是0.333...)。而Double是64位的二进制浮点数,只能存储有限位数的近似值,所以你定义的radius其实不是精确的10.2,只是一个非常接近它的近似值。
当你用这个近似值乘以100时,原本藏在小数点后的微小误差被放大,就出现了1019.9999999999999;而乘以10或者1000时,误差刚好被抵消或者没显现出来,所以结果看起来是对的。
怎么解决?
如果你的场景需要精确的十进制计算(比如涉及金钱、精确统计),别用Double,改用BigDecimal:
scala> import scala.math.BigDecimal import scala.math.BigDecimal scala> val radius = BigDecimal("10.2") // 用字符串初始化,避免继承Double的近似值 radius: scala.math.BigDecimal = 10.2 scala> radius * 100 res0: scala.math.BigDecimal = 1020
小提醒
Double适合对精度要求不高的场景(比如游戏、图形渲染),但只要是需要精确十进制运算的地方,一定要用BigDecimal哦。
内容的提问来源于stack exchange,提问作者Pan Wu

