dev: rename/improve amountSetFullPrecisionUpTo, add mixedAmountSetFullPrecisionUpTo

This commit is contained in:
Simon Michael 2024-02-29 12:31:07 -10:00
parent ce0990d1e2
commit 3ec432bd53
4 changed files with 29 additions and 18 deletions

View File

@ -97,7 +97,7 @@ module Hledger.Data.Amount (
amountSetPrecisionMax,
withPrecision,
amountSetFullPrecision,
amountSetFullPrecisionOr,
amountSetFullPrecisionUpTo,
amountInternalPrecision,
amountDisplayPrecision,
defaultMaxPrecision,
@ -159,6 +159,7 @@ module Hledger.Data.Amount (
wbUnpack,
mixedAmountSetPrecision,
mixedAmountSetFullPrecision,
mixedAmountSetFullPrecisionUpTo,
mixedAmountSetPrecisionMin,
mixedAmountSetPrecisionMax,
@ -453,24 +454,26 @@ amountSetFullPrecision a = amountSetPrecision p a
-- | We often want to display "infinite decimal" amounts rounded to some readable
-- number of digits, while still displaying amounts with a large "non infinite" number
-- of decimal digits (eg, 100 or 200 digits) in full.
-- number of digits, while still displaying amounts with a large but "non infinite"
-- number of decimal digits (eg 10 or 100 or 200 digits) in full.
-- This helper is like amountSetFullPrecision, but with some refinements:
-- 1. If the internal precision is the maximum (255), indicating an infinite decimal,
-- the display precision is set to a smaller hard-coded default (8).
-- 2. A maximum display precision can be specified, setting a hard upper limit.
--
-- 1. A maximum display precision can be specified, setting a hard upper limit.
--
-- 2. If no limit is specified, and the internal precision is the maximum (255),
-- indicating an infinite decimal, display precision is set to a smaller default (8).
--
-- This function always sets an explicit display precision (ie, Precision n).
amountSetFullPrecisionOr :: Maybe Word8 -> Amount -> Amount
amountSetFullPrecisionOr mmaxp a = amountSetPrecision (Precision p2) a
--
amountSetFullPrecisionUpTo :: Maybe Word8 -> Amount -> Amount
amountSetFullPrecisionUpTo mmaxp a = amountSetPrecision (Precision p) a
where
p1 = if -- dbg0 "maxdigits" $
amountHasMaxDigits a then defaultMaxPrecision else max disp intp
-- & dbg0 "p1"
p = case mmaxp of
Just maxp -> min maxp $ max disp intp
Nothing -> if amountHasMaxDigits a then defaultMaxPrecision else max disp intp
where
intp = amountInternalPrecision a
disp = amountDisplayPrecision a
p2 = maybe p1 (min p1) mmaxp
-- & dbg0 "p2"
intp = amountInternalPrecision a
-- | The fallback display precision used when showing amounts
-- representing an infinite decimal.
@ -1228,6 +1231,14 @@ mixedAmountSetPrecision p = mapMixedAmountUnsafe (amountSetPrecision p)
mixedAmountSetFullPrecision :: MixedAmount -> MixedAmount
mixedAmountSetFullPrecision = mapMixedAmountUnsafe amountSetFullPrecision
-- | In each component amount, increase the display precision sufficiently
-- to render it exactly if possible, but not more than the given max precision,
-- and if no max precision is given and the amount has infinite decimals,
-- limit display precision to a hard-coded smaller number (8).
-- See amountSetFullPrecisionUpTo.
mixedAmountSetFullPrecisionUpTo :: Maybe Word8 -> MixedAmount -> MixedAmount
mixedAmountSetFullPrecisionUpTo mmaxp = mapMixedAmountUnsafe (amountSetFullPrecisionUpTo mmaxp)
-- | In each component amount, ensure the display precision is at least the given value.
-- Makes all amounts have an explicit Precision.
mixedAmountSetPrecisionMin :: Word8 -> MixedAmount -> MixedAmount

View File

@ -115,7 +115,7 @@ amountPriceDirectiveFromCost :: Day -> Amount -> Maybe PriceDirective
amountPriceDirectiveFromCost d amt@Amount{acommodity=fromcomm, aquantity=n} = case acost amt of
Just (UnitCost u) -> Just $ pd{pdamount=u}
Just (TotalCost t) | n /= 0 -> Just $ pd{pdamount=u}
where u = amountSetFullPrecisionOr Nothing $ divideAmount n t
where u = amountSetFullPrecisionUpTo Nothing $ divideAmount n t
_ -> Nothing
where
pd = PriceDirective{pddate = d, pdcommodity = fromcomm, pdamount = nullamt}
@ -209,7 +209,7 @@ amountValueAtDate priceoracle styles mto d a =
-- set the display precision to match the internal precision (showing all digits),
-- unnormalised (don't strip trailing zeros);
-- but if it looks like an infinite decimal, limit the precision to 8.
& amountSetFullPrecisionOr Nothing
& amountSetFullPrecisionUpTo Nothing
& dbg9With (lbl "calculated value".showAmount)
-- | Calculate the gain of each component amount, that is the difference

View File

@ -107,7 +107,7 @@ reversePriceDirective pd@PriceDirective{pdcommodity=c, pdamount=a}
where
lbl = lbl_ "reversePriceDirective"
a' =
amountSetFullPrecisionOr (Just defaultMaxPrecision) $
amountSetFullPrecisionUpTo (Just defaultMaxPrecision) $
invertAmount a{acommodity=c}
& dbg9With (lbl "calculated reverse price".showAmount)
-- & dbg9With (lbl "precision of reverse price".show.amountDisplayPrecision)

View File

@ -147,7 +147,7 @@ roi CliOpts{rawopts_=rawopts, reportspec_=rspec@ReportSpec{_rsReportOpts=ReportO
, T.pack $ showMixedAmount $ styleAmounts styles $ cashFlowAmt
-- , T.pack $ showMixedAmount $
-- -- dbg0With (lbl "cashflow after styling".showMixedAmountOneLine) $
-- mapMixedAmount (amountSetFullPrecisionOr (Just defaultMaxPrecision)) $
-- mapMixedAmount (amountSetFullPrecisionUpTo (Just defaultMaxPrecision)) $
-- styleAmounts (styles
-- -- & dbg0With (lbl "styles".show))
-- cashFlowAmt