[IMP] odoo.tools: add HALF-EVEN and HALF-DOWN to float_round
Add support for `HALF-EVEN` and `HALF-DOWN` as value for `rounding_method` argument of `float_round()`. closes odoo/odoo#152227 Signed-off-by: Raphael Collet <rco@odoo.com>
This commit is contained in:
@@ -71,8 +71,10 @@ class TestFloatPrecision(TransactionCase):
|
||||
result = float_repr(value, precision_digits=digits)
|
||||
self.assertEqual(result, expected, 'Rounding error: got %s, expected %s' % (result, expected))
|
||||
|
||||
try_round(2.6745, '2.675')
|
||||
try_round(-2.6745, '-2.675')
|
||||
try_round(2.6735, '2.674') # Tie rounds away from 0
|
||||
try_round(-2.6735, '-2.674') # Tie rounds away from 0
|
||||
try_round(2.6745, '2.675') # Tie rounds away from 0
|
||||
try_round(-2.6745, '-2.675') # Tie rounds away from 0
|
||||
try_round(2.6744, '2.674')
|
||||
try_round(-2.6744, '-2.674')
|
||||
try_round(0.0004, '0.000')
|
||||
@@ -82,6 +84,34 @@ class TestFloatPrecision(TransactionCase):
|
||||
try_round(457.4554, '457.455')
|
||||
try_round(-457.4554, '-457.455')
|
||||
|
||||
# Try some rounding value with rounding method HALF-DOWN instead of HALF-UP
|
||||
try_round(2.6735, '2.673', method='HALF-DOWN') # Tie rounds towards 0
|
||||
try_round(-2.6735, '-2.673', method='HALF-DOWN') # Tie rounds towards 0
|
||||
try_round(2.6745, '2.674', method='HALF-DOWN') # Tie rounds towards 0
|
||||
try_round(-2.6745, '-2.674', method='HALF-DOWN') # Tie rounds towards 0
|
||||
try_round(2.6744, '2.674', method='HALF-DOWN')
|
||||
try_round(-2.6744, '-2.674', method='HALF-DOWN')
|
||||
try_round(0.0004, '0.000', method='HALF-DOWN')
|
||||
try_round(-0.0004, '-0.000', method='HALF-DOWN')
|
||||
try_round(357.4555, '357.455', method='HALF-DOWN')
|
||||
try_round(-357.4555, '-357.455', method='HALF-DOWN')
|
||||
try_round(457.4554, '457.455', method='HALF-DOWN')
|
||||
try_round(-457.4554, '-457.455', method='HALF-DOWN')
|
||||
|
||||
# Try some rounding value with rounding method HALF-EVEN instead of HALF-UP
|
||||
try_round(2.6735, '2.674', method='HALF-EVEN') # Tie rounds to the closest even number (i.e. up here)
|
||||
try_round(-2.6735, '-2.674', method='HALF-EVEN') # Tie rounds to the closest even number (i.e. up here)
|
||||
try_round(2.6745, '2.674', method='HALF-EVEN') # Tie rounds to the closest even number (i.e. down here)
|
||||
try_round(-2.6745, '-2.674', method='HALF-EVEN') # Tie rounds to the closest even number (i.e. down here)
|
||||
try_round(2.6744, '2.674', method='HALF-EVEN')
|
||||
try_round(-2.6744, '-2.674', method='HALF-EVEN')
|
||||
try_round(0.0004, '0.000', method='HALF-EVEN')
|
||||
try_round(-0.0004, '-0.000', method='HALF-EVEN')
|
||||
try_round(357.4555, '357.455', method='HALF-EVEN')
|
||||
try_round(-357.4555, '-357.455', method='HALF-EVEN')
|
||||
try_round(457.4554, '457.455', method='HALF-EVEN')
|
||||
try_round(-457.4554, '-457.455', method='HALF-EVEN')
|
||||
|
||||
# Try some rounding value with rounding method UP instead of HALF-UP
|
||||
# We use 8.175 because when normalizing 8.175 with precision_digits=3 it gives
|
||||
# us 8175,0000000001234 as value, and if not handle correctly the rounding UP
|
||||
|
||||
@@ -45,10 +45,13 @@ def float_round(value, precision_digits=None, precision_rounding=None, rounding_
|
||||
:param float precision_rounding: decimal number representing the minimum
|
||||
non-zero value at the desired precision (for example, 0.01 for a
|
||||
2-digit precision).
|
||||
:param rounding_method: the rounding method used: 'HALF-UP', 'UP' or 'DOWN',
|
||||
the first one rounding up to the closest number with the rule that
|
||||
number>=0.5 is rounded up to 1, the second always rounding up and the
|
||||
latest one always rounding down.
|
||||
:param rounding_method: the rounding method used:
|
||||
- 'HALF-UP' will round to the closest number with ties going away from zero.
|
||||
- 'HALF-DOWN' will round to the closest number with ties going towards zero.
|
||||
- 'HALF_EVEN' will round to the closest number with ties going to the closest
|
||||
even number.
|
||||
- 'UP' will always round away from 0.
|
||||
- 'DOWN' will always round towards 0.
|
||||
:return: rounded float
|
||||
"""
|
||||
rounding_factor = _float_check_precision(precision_digits=precision_digits,
|
||||
@@ -90,6 +93,17 @@ def float_round(value, precision_digits=None, precision_rounding=None, rounding_
|
||||
normalized_value += sign*epsilon
|
||||
rounded_value = math.floor(abs(normalized_value)) * sign
|
||||
|
||||
# TIE-BREAKING: HALF-EVEN
|
||||
# We want to apply HALF-EVEN tie-breaking rules, i.e. 0.5 rounds towards closest even number.
|
||||
elif rounding_method == 'HALF-EVEN':
|
||||
rounded_value = math.copysign(builtins.round(normalized_value), normalized_value)
|
||||
|
||||
# TIE-BREAKING: HALF-DOWN
|
||||
# We want to apply HALF-DOWN tie-breaking rules, i.e. 0.5 rounds towards 0.
|
||||
elif rounding_method == 'HALF-DOWN':
|
||||
normalized_value -= math.copysign(epsilon, normalized_value)
|
||||
rounded_value = round(normalized_value)
|
||||
|
||||
# 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:
|
||||
|
||||
Reference in New Issue
Block a user