From 07198e326daaf52709303c7e27296f8b8a2d2ecb Mon Sep 17 00:00:00 2001 From: Denis Merigoux Date: Fri, 6 May 2022 15:28:09 +0200 Subject: [PATCH] Fixed rounding bug in interpreter for negative values --- compiler/runtime.ml | 10 +++++++--- runtimes/python/catala/src/catala/runtime.py | 2 ++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/compiler/runtime.ml b/compiler/runtime.ml index b1f74fb9..095c2354 100644 --- a/compiler/runtime.ml +++ b/compiler/runtime.ml @@ -233,12 +233,16 @@ let handle_default_opt let no_input : unit -> 'a = fun _ -> raise EmptyError let ( *$ ) (i1 : money) (i2 : decimal) : money = - let rat_result = Q.mul (Q.of_bigint i1) i2 in + let i1_abs = Z.abs i1 in + let i2_abs = Q.abs i2 in + let sign_int = Z.sign i1 * Q.sign i2 in + let rat_result = Q.mul (Q.of_bigint i1_abs) i2_abs in let res, remainder = Z.div_rem (Q.num rat_result) (Q.den rat_result) in (* we perform nearest rounding when multiplying an amount of money by a decimal !*) - if Z.(of_int 2 * remainder >= Q.den rat_result) then Z.add res (Z.of_int 1) - else res + if Z.(of_int 2 * remainder >= Q.den rat_result) then + Z.(add res (of_int 1) * of_int sign_int) + else Z.(res * of_int sign_int) let ( /$ ) (m1 : money) (m2 : money) : decimal = if Z.zero = m2 then raise Division_by_zero diff --git a/runtimes/python/catala/src/catala/runtime.py b/runtimes/python/catala/src/catala/runtime.py index 977dd2a6..0e3ec080 100644 --- a/runtimes/python/catala/src/catala/runtime.py +++ b/runtimes/python/catala/src/catala/runtime.py @@ -138,6 +138,8 @@ class Money: def __mul__(self, other: Decimal) -> 'Money': cents = self.value.value coeff = other.value + # TODO: change, does not work with negative values. Must divide the + # absolute values and then multiply by the resulting sign. rat_result = self.value.value * other.value out = Money(Integer(rat_result)) res, remainder = t_divmod(rat_result.numerator, rat_result.denominator)