0

We all know the rounding issues in Python -- that it's based on float point arithmetic, which is convenient for computers but does not always match practical, human understanding. There's plenty of questions on this on StackOverflow, though most revolve around preserving tiny decimal places, which is different than what I need below.

The solution to these rounding issues is to use the decimal module. Yet, I must be doing something very wrong. Please, consider this, in Octave/Matlab:

>> round(2.5)
ans =  3

>> round(3.5)
ans =  4

The above are the correct results (valid in finance, applied physics, medicine, etc). We know that the same will fail in Python:

>>> round(2.5)
2

>>> round(3.5)
4

No suprise here. But when I use decimal, I still don't receive the correct answer, and here I must be doing something wrong. Starting from the example in https://docs.python.org/3/library/decimal.html:

>>> from decimal import *
>>> TWOPLACES = Decimal(10) ** -2   # same as Decimal('0.01')
>>> # Round to two places
>>> Decimal('3.214').quantize(TWOPLACES)
Decimal('3.21')

Straightforward, right? But then:

>>> Decimal('3.225').quantize(TWOPLACES)
Decimal('3.22')   # Wrong result. Correct would be 3.23

>>> Decimal('3.235').quantize(TWOPLACES)
Decimal('3.24')   # Correct result.

So, what can I do to have the correct (as in "real world", "human-based") answer, in a fast, efficient, pythonic manner, and use the result in further computations?

EDIT: I'm using Python 3.7.3.

amwink
  • 1
  • Did you notice that the `quantize` method takes a `rounding` argument to specify the rounding mode? https://docs.python.org/3/library/decimal.html#decimal.Decimal.quantize – Mark Dickinson Jul 23 '21 at 13:51
  • Why is rounding 3.225 to 3.22 wrong and rounding to 3.23 correct? – mkrieger1 Jul 23 '21 at 13:51
  • @MarkDickinson I hadn't, thank you. This solved the problem. – amwink Jul 23 '21 at 14:11
  • @mkrieger1: It's arguable what would be right or not. Let's say that rounding 0.5 upwards ensures that results remain accurate (up to whatever number of significant digits we are using) as computations accumulate. Of course other rounding schemes have their uses, but crucially, it seems that without using this "rounding" parameter, the result doesn't seem to be consistent (well, of course it is, but the consistency doesn't match our common, daily use). Thanks for commenting! – amwink Jul 23 '21 at 14:15

1 Answers1

3

This happens by design and is not an error.

See answers to this question as to why this happens: Python 3.x rounding behavior

You can set the desired rounding method as a parameter of quantize:

Decimal('3.235').quantize(TWOPLACES, rounding=ROUND_HALF_UP)
Uretki
  • 197
  • 9
  • Excellent, I hadn't seen that this parameter existed, and indeed, of the ones in the documentation, it's the ROUND_HALF_UP that will do what is needed. Thanks. – amwink Jul 23 '21 at 14:10