Спрей-json JsNumber BigDecimal isValid* странность

Может кто-нибудь объяснить мне это:

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, и это мои библиотеки LibraryDependencies:

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

Спасибо Грега

1 ответ

Проблема в том, что преобразование из BigDecimal в float не является идеальным, поэтому возвращает false. FloatValue должно выполнить некоторое округление. Заметим:

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

Но когда вы пытаетесь конвертировать BigDecimal -> Float -> 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 хорошо работает с произвольными десятичными числами, с плавающей запятой хранится в степенях два, поэтому вместо 0,16 лучшее, что он может сделать, - это получить очень близкое значение 0,1599999964237213, но, поскольку есть некоторая потеря, isValidFloat возвращает false.

Другие вопросы по тегам