Python rounding issue and how to fix it

Consider the following piece of code:

print(f"3.625 -> {round(3.625, 2)}")
print(f"3.635 -> {round(3.635, 2)}")
print(f"3.645 -> {round(3.645, 2)}")
print(f"3.655 -> {round(3.655, 2)}")
print(f"3.665 -> {round(3.665, 2)}")

The code above produces the following output:

3.625 -> 3.62
3.635 -> 3.63
3.645 -> 3.65
3.655 -> 3.65
3.665 -> 3.67

Strange, isn’t it? The values which end with “5” should be rounded up! This is a common issue, because the float number which is stored as binary, is not represented exactly the same as in decimals. This is the source of the issue.

Thankfully, there is a simple way to fix this. Take a look at this function and the code:

import math


def round_with_half_up(number_to_round, decimals=0):
    multiply_by = 10 ** decimals
    return math.floor(number_to_round * multiply_by + 0.5) / multiply_by


print(f"3.625 -> {round_with_half_up(3.625, 2)}")
print(f"3.635 -> {round_with_half_up(3.635, 2)}")
print(f"3.645 -> {round_with_half_up(3.645, 2)}")
print(f"3.655 -> {round_with_half_up(3.655, 2)}")
print(f"3.665 -> {round_with_half_up(3.665, 2)}")

Now, the result looks like expected:

3.625 -> 3.63
3.635 -> 3.64
3.645 -> 3.65
3.655 -> 3.66
3.665 -> 3.67

The above function works fine also for other numbers, not only for the ones that end with “5” 🙂