Closed sanpii closed 1 year ago
Yes, this is expected behavior now. The floating point value 20_000.000001_f64
cannot be "trusted" as a decimal value, as binary representations can only exactly represent numbers as sums of 2^-n (just how humans prefer decimal numbers, which only represent sums of 10^-n).
Putting 20000.000001 into https://baseconvert.com/ieee-754-floating-point confirms this is the correct result: 20000.0000010000003385357558727264404296875
Same with Python's Decimal library:
>>> from decimal import Decimal
>>> Decimal(20_000.000001)
Decimal('20000.0000010000003385357558727264404296875')
It's also true for 0.1
:
>>> Decimal(0.1)
Decimal('0.1000000000000000055511151231257827021181583404541015625')
And I'm sure this is standard behavior for decimal libraries.
This is actually the primary reason you use decimal libraries, as the floating point values we are shown are often lies
>>> Decimal(0.3)
Decimal('0.299999999999999988897769753748434595763683319091796875')
>>> Decimal(0.1 + 0.2)
Decimal('0.3000000000000000444089209850062616169452667236328125')
>>> 0.3 < 0.1+0.2
True
vs dealing with sums of negative-two powers:
>>> 2**-1 + 2**-5
0.53125
>>> Decimal(2**-1 + 2**-5)
Decimal('0.53125')
This was the previous implementation, which wrote the given number to an allocated string in exponential form with fixed precision:
BigDecimal::from_str(
&format!("{:.PRECISION$e}", n, PRECISION = ::std::f64::DIGITS as usize)
)
(std::f64::DIGITS == 15
)
Which for your case would parse 2.000000000100000e4
(playground)
That implementation was replaced with a couple bit shifts and masks.
What specifically broke? Or was this just unexpected behavior?
Apparently BigDecimal Ruby gem disallows building BigDecimal from float without specifying precision: https://github.com/ruby/bigdecimal/blob/master/test/bigdecimal/test_bigdecimal.rb#L167
That doesn't really work for us if we want to keep the trait.
Ok, thank you for your explanation.
That breaks unit tests in my case, nothing critical.
With the last release (
0.4.0
), this code no longer works: