Skip to content

Commit 21a84fb

Browse files
committed
fix: calculate value correctly when P amounts have few decimal digits [#2254]
Valuation in another commoditay could sometimes be inaccurate if the P price amounts did not have enough decimal places.
1 parent 4e6f661 commit 21a84fb

File tree

2 files changed

+28
-7
lines changed

2 files changed

+28
-7
lines changed

hledger-lib/Hledger/Data/Valuation.hs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ import Hledger.Data.Types
4848
import Hledger.Data.Amount
4949
import Hledger.Data.Dates (nulldate)
5050
import Text.Printf (printf)
51-
import Data.Decimal (decimalPlaces, roundTo)
51+
import Data.Decimal (decimalPlaces, roundTo, Decimal)
52+
import Data.Word (Word8)
5253

5354

5455
------------------------------------------------------------------------------
@@ -290,12 +291,17 @@ priceLookup makepricegraph d from mto =
290291
-- aggregate all the prices into one
291292
product rates
292293
-- product (Decimal's Num instance) normalises, stripping trailing zeros.
293-
-- Here we undo that (by restoring the old max precision with roundTo),
294-
-- so that amountValueAtDate can see the original internal precision,
295-
-- to use as the display precision of calculated value amounts.
296-
-- (This can add more than the original number of trailing zeros to some prices,
297-
-- making them seem more precise than they were, but it seems harmless here.)
298-
& roundTo (maximum $ map decimalPlaces rates)
294+
-- But we want to preserve even those, since the number of decimal digits
295+
-- here will guide amountValueAtDate in setting the Amount display precision later.
296+
-- So we restore them. Or rather, we ensure as many decimal digits as the maximum seen among rates.
297+
-- (Some prices might end up more precise than they were, but that seems harmless here.)
298+
& setMinDecimalPlaces (maximum $ map decimalPlaces rates)
299+
300+
-- Ensure this Decimal has at least this many decimal places, adding trailing zeros if necessary.
301+
setMinDecimalPlaces :: Word8 -> Decimal -> Decimal
302+
setMinDecimalPlaces n d
303+
| decimalPlaces d < n = roundTo n d -- too few, add some zeros
304+
| otherwise = d -- more than enough, keep as-is
299305

300306
tests_priceLookup =
301307
let

hledger/test/journal/valuation2.test

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,3 +341,18 @@ Balance changes in 2019, valued at period ends:
341341
==========++========
342342
Assets:A || $2.00
343343
Income:B || $-2.00
344+
345+
# ** 33. #2254 Conversion rates should not be display-rounded during value calculation.
346+
# 100 * 10.5 * 100.5 = 105525
347+
<
348+
P 2000-01-01 A 10.5 B
349+
P 2000-01-01 B 100.5 C
350+
351+
2000-01-01
352+
(a) 100 A
353+
354+
$ hledger -f- print -X C
355+
2000-01-01
356+
(a) 105525 C
357+
358+
>=

0 commit comments

Comments
 (0)