As it turns out, Python does not do commercial rounding.

What is commercial rounding?

For most digits, the direction of rounding is clear. There are some special cases though: Do I round $0.5$ to $0$ or to $1$?

In commercial rounding, this “$0.5$” problem is solved by “rounding away from zero”, meaning: For positive numbers, round up; for negative numbers, round down.

This makes perfect sense for a mathematician, but others might need examples, so here are some1:

  • $0.5$ goes to $1$.
  • $-0.5$ goes to $-1$ (away from zero).

The same obviously goes in other positions too: $0.05$ goes to $0.1$, etc.

What does Python do?

Here, actually mathematical rounding happens: Round to the next even possibility. Meaning:

  • $0.5$ goes to $0$ (!).
  • $1.5$ goes to $2$.
  • $2.5$ goes to $2$ (!).

This also makes sense in some settings, which I will discuss in a later post.

How do I implement commercial rounding in Python?

I just wrote my own function,which does exactly that and is (in the cases I need) a drop-in replacement for Python’s builtin round function:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def round(val, ndigits=0):

    # Keep the sign extra, else we need more
    # cases below
    sign = 1 if val >= 0 else -1

    factor = 10**ndigits

    scaled = int(val * sign * factor * 10)
    last_digit = scaled % 10

    scaled = scaled // 10

    # Rounding: Round up if the
    # last digit is larger or equal to 5
    if last_digit >= 5:
        scaled += 1

    # Return an integer if rounding to integer
    if ndigits == 0:
        return int(scaled * sign)

    # Return the correct float
    return scaled * sign / factor

Just define this at the beginning of your module, and then use the round function as usual.

Note!

I am not fully sure about this approach: In the end, we again return a floating point number. Why will this not be approximated?


  1. I read that in a paper once, and found it funny. Sorry if you feel offended. ↩︎