diff options
| author | Christophe Simonis <chs@odoo.com> | 2018-02-01 18:15:21 +0100 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2018-02-01 18:15:21 +0100 |
| commit | 7e469eb77aae1f7e05a3ce0f6575b5149fed3ca1 (patch) | |
| tree | 25023238fd6ccde1f3b8e805b03fcf228798a7b0 /odoo/tools/float_utils.py | |
| parent | c4895c2f2ba0fcd8fc5aef210003c20ba2154979 (diff) | |
| parent | f5e7b866860436782ade53308da1ff725be1f124 (diff) | |
[MERGE] forward port branch 11.0 up to f5e7b866860
Diffstat (limited to 'odoo/tools/float_utils.py')
| -rw-r--r-- | odoo/tools/float_utils.py | 27 |
1 files changed, 15 insertions, 12 deletions
diff --git a/odoo/tools/float_utils.py b/odoo/tools/float_utils.py index 33044d21f93..041a87cabbe 100644 --- a/odoo/tools/float_utils.py +++ b/odoo/tools/float_utils.py @@ -61,9 +61,6 @@ def float_round(value, precision_digits=None, precision_rounding=None, rounding_ # In order to easily support rounding to arbitrary 'steps' (e.g. coin values), # we normalize the value before rounding it as an integer, and de-normalize # after rounding: e.g. float_round(1.3, precision_rounding=.5) == 1.5 - - # TIE-BREAKING: HALF-UP (for normal rounding) - # We want to apply HALF-UP tie-breaking rules, i.e. 0.5 rounds away from 0. # Due to IEE754 float/double representation limits, the approximation of the # real value may be slightly below the tie limit, resulting in an error of # 1 unit in the last place (ulp) after rounding. @@ -74,25 +71,31 @@ def float_round(value, precision_digits=None, precision_rounding=None, rounding_ # Credit: discussion with OpenERP community members on bug 882036 normalized_value = value / rounding_factor # normalize + sign = math.copysign(1.0, normalized_value) epsilon_magnitude = math.log(abs(normalized_value), 2) epsilon = 2**(epsilon_magnitude-53) - if rounding_method == 'HALF-UP': - normalized_value += math.copysign(epsilon, normalized_value) - rounded_value = round(normalized_value) # round to integer - # TIE-BREAKING: UP (for ceiling[resp. flooring] operations) - # When rounding the value up[resp. down], we instead subtract the epsilon value + # TIE-BREAKING: UP/DOWN (for ceiling[resp. flooring] operations) + # When rounding the value up[resp. down], we instead subtract[resp. add] the epsilon value # as the the approximation of the real value may be slightly *above* the # tie limit, this would result in incorrectly rounding up[resp. down] to the next number # The math.ceil[resp. math.floor] operation is applied on the absolute value in order to # round "away from zero" and not "towards infinity", then the sign is # restored. - else: - func = math.floor if rounding_method == 'DOWN' else math.ceil - sign = math.copysign(1.0, normalized_value) + if rounding_method == 'UP': normalized_value -= sign*epsilon - rounded_value = func(abs(normalized_value)) * sign + rounded_value = math.ceil(abs(normalized_value)) * sign + + elif rounding_method == 'DOWN': + normalized_value += sign*epsilon + rounded_value = math.floor(abs(normalized_value)) * sign + + # TIE-BREAKING: HALF-UP (for normal rounding) + # We want to apply HALF-UP tie-breaking rules, i.e. 0.5 rounds away from 0. + else: + normalized_value += math.copysign(epsilon, normalized_value) + rounded_value = round(normalized_value) # round to integer result = rounded_value * rounding_factor # de-normalize return result |
