[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Formatting numbers without precision loss
- From: Lars Müller <appgurulars@...>
- Date: Tue, 20 Jun 2023 14:03:49 +0200
Exponential binary notation is indeed the only way to exactly
represent floats. If you're in full control of the format, it's
the way to go for serializing floats; it's effectively just the
exponent plus a hexdump of the mantissa. This also makes it very
efficient and easy to implement. You could even implement this
formatting yourself in Lua.
But if your hands are tied with JSON or similar formats - or you
want human-readability - you need to format as decimal. This can't
be exact, but it can be precise enough for the conversion from
string back to number to yield the exact same number.
For this, 17 significant digits should suffice:
"The 53-bit significand precision gives from 15 to 17 significant decimal digits
precision" -
https://en.wikipedia.org/wiki/Double-precision_floating-point_format
Thus ("%.17g"):format(num) should
work. If you really want to be safe, perhaps use %.18g.
Note: Do not use %f, use %g instead. %f
does not count significant digits, it counts digits after the
decimal dot. It's also very human-unfriendly and wasteful since it
will emit trailing zeroes; the fact that it doesn't use exponents
can create very bloaty outputs for numbers with large exponents.
Here's ("%.6f"):format(2^1e3):
10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376.000000
On 20.06.23 13:49, Lorenzo Donati wrote:
Hi!
[...]
Just a hunch, since it passed too much time from when I looked
into this. I think the only fireproof way to serialize a float
number (assuming an IEEE754 implementation) is using exponential
binary notation ("%a" format specifier), but the presence of that
depends on the underlying C runtime (IIRC Lua supported that
format specifier since v5.2).
In other words, there always will be some float number whose
binary representation will be approximate by any amount of decimal
figures in a decimal representation.
There was some "good enough" approximation: IIRC %.14f worked well
for 64bit double precision IEEE754 floats. "Well" means that for
most (all?) possible numbers the approximation was under some
epsilon.
Cheers!
-- Lorenzo