From 5cfc8cf630ba65c5cff5943f4ba74aec20e8cf35 Mon Sep 17 00:00:00 2001 From: Simon Michael Date: Wed, 25 Nov 2009 19:42:13 +0000 Subject: [PATCH] fix a tricky mixedamount arithmetic bug --- Ledger/Amount.hs | 20 ++++++++++---------- Tests.hs | 11 +++++++++++ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/Ledger/Amount.hs b/Ledger/Amount.hs index 6d7dffb4a..f47cf2cfe 100644 --- a/Ledger/Amount.hs +++ b/Ledger/Amount.hs @@ -73,14 +73,19 @@ instance Ord MixedAmount where negateAmountPreservingPrice a = (-a){price=price a} --- | Apply a binary arithmetic operator to two amounts - converting to the --- second one's commodity, adopting the lowest precision, and discarding --- any price information. (Using the second commodity is best since sum --- and other folds start with a no-commodity amount.) +-- | Apply a binary arithmetic operator to two amounts, converting to the +-- second one's commodity (and display precision), discarding any price +-- information. (Using the second commodity is best since sum and other +-- folds start with a no-commodity amount.) amountop :: (Double -> Double -> Double) -> Amount -> Amount -> Amount amountop op a@(Amount _ _ _) (Amount bc bq _) = Amount bc (quantity (convertAmountTo bc a) `op` bq) Nothing +-- | Convert an amount to the specified commodity using the appropriate +-- exchange rate (which is currently always 1). +convertAmountTo :: Commodity -> Amount -> Amount +convertAmountTo c2 (Amount c1 q _) = Amount c2 (q * conversionRate c1 c2) Nothing + -- | Convert an amount to the commodity of its saved price, if any. costOfAmount :: Amount -> Amount costOfAmount a@(Amount _ _ Nothing) = a @@ -89,11 +94,6 @@ costOfAmount (Amount _ q (Just price)) | otherwise = Amount pc (pq*q) Nothing where (Amount pc pq _) = head $ amounts price --- | Convert an amount to the specified commodity using the appropriate --- exchange rate (which is currently always 1). -convertAmountTo :: Commodity -> Amount -> Amount -convertAmountTo c2 (Amount c1 q _) = Amount c2 (q * conversionRate c1 c2) Nothing - -- | Get the string representation of an amount, based on its commodity's -- display settings. showAmount :: Amount -> String @@ -208,7 +208,7 @@ normaliseMixedAmount (Mixed as) = Mixed as'' sym = symbol . commodity as' | null nonzeros = [head $ zeros ++ [nullamt]] | otherwise = nonzeros - (zeros,nonzeros) = partition isZeroAmount as + (zeros,nonzeros) = partition isReallyZeroAmount as sumSamePricedAmountsPreservingPrice [] = nullamt sumSamePricedAmountsPreservingPrice as = (sum as){price=price $ head as} diff --git a/Tests.hs b/Tests.hs index f84fe8fcf..6a51f2eb8 100644 --- a/Tests.hs +++ b/Tests.hs @@ -309,6 +309,17 @@ tests = [ sum [a2,a3] `is` Amount (comm "$") (-2.46) Nothing sum [a3,a3] `is` Amount (comm "$") (-2.46) Nothing sum [a1,a2,a3,-a3] `is` Amount (comm "$") 0 Nothing + let dollar0 = dollar{precision=0} + (sum [Amount dollar 1.25 Nothing, Amount dollar0 (-1) Nothing, Amount dollar (-0.25) Nothing]) + `is` (Amount dollar 0 Nothing) + + ,"mixed amount arithmetic" ~: do + let dollar0 = dollar{precision=0} + (sum $ map (Mixed . (\a -> [a])) + [Amount dollar 1.25 Nothing, + Amount dollar0 (-1) Nothing, + Amount dollar (-0.25) Nothing]) + `is` Mixed [Amount dollar 0 Nothing] ,"balance report tests" ~: let (opts,args) `gives` es = do