Skip to content

Commit

Permalink
Fix parsing of floats with long mantissa (#222)
Browse files Browse the repository at this point in the history
  • Loading branch information
fsvehla authored Mar 24, 2021
1 parent bd8bb12 commit c184f0e
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,10 @@ object SafeNumbersSpec extends DefaultRunnableSpec {
testM("valid") {
check(Gen.anyFloat.filterNot(_.isNaN))(d => assert(SafeNumbers.float(d.toString))(equalTo(FloatSome(d))))
},
test("large mantissa") {
// https://github.com/zio/zio-json/issues/221
assert(SafeNumbers.float("1.199999988079071"))(equalTo(FloatSome(1.1999999f)))
},
testM("valid (from Int)") {
check(Gen.anyInt)(i => assert(SafeNumbers.float(i.toString))(equalTo(FloatSome(i.toFloat))))
},
Expand Down
51 changes: 49 additions & 2 deletions zio-json/shared/src/main/scala/zio/json/internal/numbers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -263,11 +263,58 @@ object UnsafeNumbers {

def float(num: String, max_bits: Int): Float =
float_(new FastStringReader(num), true, max_bits)
def float_(in: Reader, consume: Boolean, max_bits: Int): Float =
double_(in, consume, max_bits).toFloat

def float_(in: Reader, consume: Boolean, max_bits: Int): Float = {
var current: Int = in.read()
var negative = false

def readAll(s: String): Unit = {
var i = 0
val len = s.length

while (i < len) {
current = in.read()
if (current != s(i)) throw UnsafeNumber
i += 1
}

current = in.read() // to be consistent read the terminator

if (consume && current != -1)
throw UnsafeNumber
}

if (current == 'N') {
readAll("aN")
return Float.NaN
}

if (current == '-') {
negative = true
current = in.read()
} else if (current == '+') {
current = in.read()
}

if (current == 'I') {
readAll("nfinity")

if (negative) return Float.NegativeInfinity
else return Float.PositiveInfinity
}

if (current == -1)
throw UnsafeNumber

val res = bigDecimal__(in, consume, negative = negative, initial = current, int_only = false, max_bits = max_bits)

if (negative && res.unscaledValue == java.math.BigInteger.ZERO) -0.0f
else res.floatValue
}

def double(num: String, max_bits: Int): Double =
double_(new FastStringReader(num), true, max_bits)

def double_(in: Reader, consume: Boolean, max_bits: Int): Double = {
var current: Int = in.read()
var negative = false
Expand Down

0 comments on commit c184f0e

Please sign in to comment.