Description
A json serialization + deserialization round-trip does not give back the original value for floats.
Example
import json
import strformat
# some arbitrary float, not caring about actually significant places here
let x = 0.12345678901234567890123456789
let y = ($(%* x)).parseJson().getFloat()
echo &"{x} == {x} => {x == y}"
doAssert x == y
(EDIT(timotheecour): see another example in #15397 (comment))
Current Output
0.1234567890123457 == 0.1234567890123457 => false
/tmp/test.nim(9) test
/nim/lib/system/assertions.nim(27) failedAssertImpl
/nim/lib/system/assertions.nim(20) raiseAssert
/nim/lib/system/fatal.nim(55) sysFatal
Error: unhandled exception: /tmp/test.nim(9, 10) `x == y` [AssertionError]
Expected Output
No assertion error at least.
Possible Solution
This is basically a consequence that parseFloat
and $
are not supposed be lossless (see #7717), but the json module builds on these.
I made a quick check with NimYaml and it suffers from exactly the same problem.
It is a natural expectation to rely on $
to produce an exact string representation. In my opinion the easiest solution would be to improve $
for floats. Perhaps it would make sense to implement Ryū: fast float-to-string conversion in the Nim standard library to solve the problem for good. A reference implementation is available in C and other languages. This would probably give float-to-string conversion a nice performance boost as well.
$ nim -v
Nim Compiler Version 1.1.1 [Linux: amd64]
Compiled at 2020-01-19
Copyright (c) 2006-2019 by Andreas Rumpf
git hash: 13ddbc46fc255978ebaf4233009b44db29583cb4
active boot switches: -d:release