Understanding Python’s Round Function: From Basics to Bankers

Akhil Nath Elayat
4 min readNov 6, 2023

--

In the world of computation, where precision matters, rounding plays a pivotal role. Especially when we present data to users or make decisions based on computed values, how we round off numbers can make a difference. Python simplifies this with its round function, which does more than just truncate decimals.

Understanding Basic Rounding: Rounding in Python is straightforward when using the round function.

Syntax: round(number, n_digits=None)

number is the value to round

n_digits is the optional number of decimals to keep.

The Python round function returns a floating-point number rounded off to the specified number of decimals. In most cases, it follows rounding to the nearest 10^-(n_digits) value. The behavior changes based on the value of n_digits:

  • n_digits = 0: Rounds to the nearest integer. For instance, round(1.6) returns 2.
  • n_digits > 0: Rounds to the specified number of decimals. Example: round(1.8888, 2) yields 1.89. In this case, it rounds to the nearest 10^-(2), i.e., rounding to the nearest multiple of .01.
  • n_digits < 0: Rounds off to the left of the decimal. For example, round(888.88, -1) results in 890. In this case, it rounds to the nearest 10^-(-1), i.e., rounding to the nearest multiple of 10.

Tackling Ties: Rounding isn’t always as straightforward as it seems, especially when we deal with ties. A tie occurs when the number is equidistant from the two numbers it can round to. Take 2.5. Does it round to 2 or 3?

Traditional rounding, the kind we often learn in school, follows the principle of “rounding to closest, ties away from zero”. By this logic:

  • 1.5 rounds to 2
  • 2.5 rounds to 3
  • -1.5 rounds to -2
  • -2.5 rounds to -3

However, Python’s results differ:

  • round(1.5) gives 2
  • round(2.5) results in 2
  • round(-1.5) gives -2
  • round(-2.5) results in –2

Banker’s Rounding:

Here’s where Python throws a curveball. Instead of the traditional method, Python uses what’s known as “Banker’s Rounding” or “round half to even”. In this method, if a number is equidistant between two others, it rounds to the nearest even number. This method reduces the cumulative error when adding rounded numbers together, making it popular in financial systems. In banker’s rounding, a number is rounded to the nearest value, with ties rounded to the nearest value with an even least significant digit (i.e., the rightmost digit except trailing zeros).

  • round(1.5) returns 2: Here, 1.5 is equidistant between 1 and 2 and rounds to 2 because the least significant digit is 2, which is even.
  • round(2.5) returns 2: Here, 2.5 is equidistant between 2 and 3 and also rounds to 2.
  • round(-1.5) returns -2
  • round(-2.5) returns -2
  • round(1.25, 1) returns 1.2: Here, 1.25 is equidistant between 1.2 and 1.3 and rounds down to 1.2.
  • round(1.35, 1) returns 1.4: And 1.35 is equidistant between 1.3 and 1.4 and rounds up to 1.4.

Advantages of Bankers Rounding:

Python’s choice aligns with the goal of reducing bias over multiple calculations, making it particularly apt for financial and statistical applications.

Let’s examine an example that demonstrates the rounding of a list of numbers:

import statistics

# Generate a list of numbers from 0.5 to 99.5
numbers = [i + 0.5 for i in range(100)]

# Conventional rounding: Create a custom rounding function
def conventional_round(number):
return int(number + 0.5)

# Apply conventional rounding
conventional_rounded_numbers = [conventional_round(number) for number in numbers]

# Apply Banker's rounding
bankers_rounded_numbers = [round(number) for number in numbers]

# Calculate the average difference from the original numbers
avg_diff_conventional = statistics.mean([abs(x - y) for x, y in zip(numbers, conventional_rounded_numbers)])
avg_diff_bankers = statistics.mean([abs(x - y) for x, y in zip(numbers, bankers_rounded_numbers)])

print("Average difference with conventional rounding:", avg_diff_conventional)
print("Average difference with Banker's rounding:", avg_diff_bankers)

Output:

Average difference with conventional rounding: 0.5

Average difference with Banker’s rounding: 0.25

Running this code would typically show a lower average difference for Banker’s rounding when compared to conventional rounding, demonstrating the reduced bias. This difference may not be significant in a small range like 0.5 to 99.5, but as the range increases and the numbers become more varied, the effect of rounding can have a statistically significant impact on the sum or average of large datasets.

Custom Rounding: While Python’s in-built round function follows the Banker's Rounding method, you aren't restricted to it. You can implement the traditional rounding method using custom functions. For instance, by adding 0.5 to a positive number and truncating the result, you can achieve traditional rounding. This could look like this:

from math import copysign


def _round(x):
return int(x + 0.5 * copysign(1, x))

Using this, _round(2.5) will indeed return 3.

Conclusion:

The way we round numbers might seem trivial, but in applications where precision and representation matter, it’s a critical consideration. Whether you’re presenting financial data, scientific findings, or striving for readability, the rounding method you choose has implications. Python offers both flexibility and precision, accommodating different rounding strategies to suit diverse needs. So, dive in, experiment, and round with confidence!

--

--