Skip to content

Commit

Permalink
fix: calculate value correctly when P amounts have few decimal digits [
Browse files Browse the repository at this point in the history
…#2254]

Valuation in another commoditay could sometimes be inaccurate if the P
price amounts did not have enough decimal places.
  • Loading branch information
simonmichael committed Oct 9, 2024
1 parent 4e6f661 commit 21a84fb
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 7 deletions.
20 changes: 13 additions & 7 deletions hledger-lib/Hledger/Data/Valuation.hs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ import Hledger.Data.Types
import Hledger.Data.Amount
import Hledger.Data.Dates (nulldate)
import Text.Printf (printf)
import Data.Decimal (decimalPlaces, roundTo)
import Data.Decimal (decimalPlaces, roundTo, Decimal)
import Data.Word (Word8)


------------------------------------------------------------------------------
Expand Down Expand Up @@ -290,12 +291,17 @@ priceLookup makepricegraph d from mto =
-- aggregate all the prices into one
product rates
-- product (Decimal's Num instance) normalises, stripping trailing zeros.
-- Here we undo that (by restoring the old max precision with roundTo),
-- so that amountValueAtDate can see the original internal precision,
-- to use as the display precision of calculated value amounts.
-- (This can add more than the original number of trailing zeros to some prices,
-- making them seem more precise than they were, but it seems harmless here.)
& roundTo (maximum $ map decimalPlaces rates)
-- But we want to preserve even those, since the number of decimal digits
-- here will guide amountValueAtDate in setting the Amount display precision later.
-- So we restore them. Or rather, we ensure as many decimal digits as the maximum seen among rates.
-- (Some prices might end up more precise than they were, but that seems harmless here.)
& setMinDecimalPlaces (maximum $ map decimalPlaces rates)

-- Ensure this Decimal has at least this many decimal places, adding trailing zeros if necessary.
setMinDecimalPlaces :: Word8 -> Decimal -> Decimal
setMinDecimalPlaces n d
| decimalPlaces d < n = roundTo n d -- too few, add some zeros
| otherwise = d -- more than enough, keep as-is

tests_priceLookup =
let
Expand Down
15 changes: 15 additions & 0 deletions hledger/test/journal/valuation2.test
Original file line number Diff line number Diff line change
Expand Up @@ -341,3 +341,18 @@ Balance changes in 2019, valued at period ends:
==========++========
Assets:A || $2.00
Income:B || $-2.00

# ** 33. #2254 Conversion rates should not be display-rounded during value calculation.
# 100 * 10.5 * 100.5 = 105525
<
P 2000-01-01 A 10.5 B
P 2000-01-01 B 100.5 C

2000-01-01
(a) 100 A

$ hledger -f- print -X C
2000-01-01
(a) 105525 C

>=

0 comments on commit 21a84fb

Please sign in to comment.