summaryrefslogtreecommitdiff
path: root/odoo/tools
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2018-02-01 18:15:21 +0100
committerChristophe Simonis <chs@odoo.com>2018-02-01 18:15:21 +0100
commit7e469eb77aae1f7e05a3ce0f6575b5149fed3ca1 (patch)
tree25023238fd6ccde1f3b8e805b03fcf228798a7b0 /odoo/tools
parentc4895c2f2ba0fcd8fc5aef210003c20ba2154979 (diff)
parentf5e7b866860436782ade53308da1ff725be1f124 (diff)
[MERGE] forward port branch 11.0 up to f5e7b866860
Diffstat (limited to 'odoo/tools')
-rw-r--r--odoo/tools/float_utils.py27
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