Keep a rational allocation amount exact - #1231
Conversation
A rational was converted through a float, so one part of 1/3 was not 1/3.
sunny
left a comment
There was a problem hiding this comment.
Thank you. Can you add an entry to the CHANGELOG as well please?
yukideluxe
left a comment
There was a problem hiding this comment.
Thanks for fixing this! Just one comment (apart from adding the CHANGELOG line that @sunny requested) so we can wrap this up nicely 👍🏻
| number | ||
| elsif number.is_a? Rational | ||
| BigDecimal(number.to_f.to_s) | ||
| number.to_d |
There was a problem hiding this comment.
Money has this customizable option
Lines 139 to 142 in 7348778
number.to_d((Money.conversion_precision). According to Claude there are more places that it might not be respected but I need to look into this a bit more and it's totally unrelated to this PR anyways 😊
The tests will have to be tweaked too 🙏🏻
Allocation of 1/3 used to_d with no precision. It now uses Money.conversion_precision.
|
Thanks, both notes are in. The changelog line is under Unreleased, and a Rational now goes through |
|
|
||
| it "keeps a rational amount instead of a float approximation" do | ||
| amount = Rational(1, 3) | ||
| expect(described_class.generate(amount, 1, false)).to eq([amount.to_d(Money.conversion_precision)]) |
There was a problem hiding this comment.
this test is running the code it tests and it currently passes in main so it's not actually testing the changes. Claudito suggests the following assertions and those look good to me!
it "converts a rational with Money.conversion_precision instead of through a float" do
expect(described_class.generate(Rational(2, 3), 1, false)).to eq([BigDecimal("0.6666666666666667")])
expect(described_class.generate(Rational(10**400, 1), 1, false)).to eq([BigDecimal("1e400")])
expect(described_class.generate(Rational(1, 10**400), 1, false)).to eq([BigDecimal("1e-400")])
endThe previous example compared the result to the same to_d call, so it passed on main. 2/3, 1e400, and 1e-400 are now fixed expected values.
|
Updated the spec to those three values. Rational(2, 3) is 0.6666666666666667, 10400 stays 1e400, and 1/10400 stays 1e-400. The conversion still goes through Money.conversion_precision. |
Summary
Money::Allocation.generate(Rational(1, 3), 1, false)returned0.3333333333333333. The rational was converted through a float, so one part was not the original amount.to_d. One part of1/3matchesRational(1, 3).to_d.Test plan
to_dvalue and got the float approximationrspec spec/money/allocation_spec.rb(23 examples, 0 failures)Made with Cursor