Spray-json JsNumber BigDecimal isValid * strangeness

时间:2014-06-12 15:55:23

标签: scala spray spray-json

有人可以向我解释一下:

scala> import spray.json._

import spray.json._



scala> import DefaultJsonProtocol._

import DefaultJsonProtocol._


scala> def check(n: BigDecimal) = {

     |     println(s"n.isValidByte = ${n.isValidByte}")

     |     println(s"n.isValidChar = ${n.isValidChar}")

     |     println(s"n.isValidDouble = ${n.isValidDouble}")

     |     println(s"n.isValidFloat = ${n.isValidFloat}")

     |     println(s"n.isValidInt = ${n.isValidInt}")

     |     println(s"n.isValidLong = ${n.isValidLong}")

     |     println(s"n.isValidShort = ${n.isValidShort}")

     | }

check: (n: BigDecimal)Unit

scala> check(JsNumber(0.16) match { case JsNumber(x) => x})

n.isValidByte = false

n.isValidChar = false

n.isValidDouble = false

n.isValidFloat = false

n.isValidInt = false

n.isValidLong = false

n.isValidShort = false

我使用的是spray-json 1.2.6,使用Scala 2.10.3,这些是我的库依赖项:

  

" io.spray" %%" spray-json" %" 1.2.6"

谢谢, Grega

1 个答案:

答案 0 :(得分:0)

问题是从BigDecimal到float的转换并不完美,所以它返回false。 floatValue必须进行一些舍入。观察:

BigDecimal(.16).floatValue                      //> res8: Float = 0.16

但是当你尝试转换BigDecimal时 - >浮动 - > BigDecimal你看到舍入错误:

BigDecimal(BigDecimal(.16).floatValue)          //> res8: scala.math.BigDecimal = 0.1599999964237213

如果您选择了一个可以用2的幂精确表示的不同值,那么您的检查功能将起作用:

  BigDecimal(BigDecimal(.5).floatValue)           //> res10: scala.math.BigDecimal = 0.5
  BigDecimal(.5).isValidFloat                     //> res11: Boolean = true

TLDR BigDecimal可以很好地执行任意小数,浮点数存储为2的幂,所以它最好能做的最好是得到非常接近0.1599999964237213但是因为有一些损失,所以isValidFloat返回false。