DEV Community

Tom Nijhof
Tom Nijhof

Posted on

1

The weird quirk with rounding in Python (and that is good)

When working with rounding in Python, you may have come across an unexpected quirk. Unlike most people who tend to round numbers ending in .5 up, Python operates differently. While it rounds 0.5 to 0, it rounds 1.5 to 2, following the international standard (IEEE 754). This may be seen as a feature or a bug, depending on how you view it.

The Python logo surrounded by different examples of rounding

It is a bug, for me!

If you encounter a bug when working with numbers ending in .5 I recommend utilizing the build library decimal. Within this library, there is a function that rounds all numbers ending with .5 up by using the ROUND_HALF_UP mode. This mode can be found in the documentation, along with other options for rounding. By incorporating this function into our code, we can ensure that any numbers ending in .5 are rounded correctly and avoid potential bugs.

I do NOT recommend using this unless it specifically causes a bug!

    from decimal import Decimal as D, ROUND_HALF_UP


    def round_nat(d):
        """
        Rounds all halves up
        """
        return D(d).quantize(D('1'), ROUND_HALF_UP)


    for x in range(1,100):
        d = x/10
        print(f"{d} rounds to {round_nat(d)}")
Enter fullscreen mode Exit fullscreen mode

It is a feature!

Rounding behavior in Python conforms to IEEE 754 rounding to nearest, ties to even. This is also known as bankers rounding or Dutch rounding. Guido van Rossum is not a banker but he is Dutch.
This ensures a fully random number is just as likely to round up as down. For example, let’s consider a range of numbers from 0 to 10 in increments of 0.1. If we calculate the average of these numbers, it comes out to 4.95. However, if we use the round_nat function (created in the previous chapter), we get an average of 5, due to the presence of 10 numbers ending in .5, which are all rounded up. This results in a slight bias towards a larger number. On the other hand, using native Python rounding eliminates this bias.

    all_num = [i/10 for i in range(0, 100)]
    print("average of all numbers:", sum(all_num)/len(all_num))
    all_rounded_num = [round(i) for i in all_num]
    print("average of all rounded numbers:", sum(all_rounded_num)/len(all_rounded_num))
    all_nat_rounded_num = [round_nat(i) for i in all_num]
    print("average of all natural rounded numbers:", sum(all_nat_rounded_num)/len(all_nat_rounded_num))
Enter fullscreen mode Exit fullscreen mode
    average of all numbers: 4.95
    average of all rounded numbers: 4.95
    average of all natural rounded numbers: 5
Enter fullscreen mode Exit fullscreen mode

Another way to understand it is by looking at the numbers between 0 and 1 with 1 decimal. We have 9 numbers in between, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9. To round them we need to remove 0.1 from 0.1, and add 0.1 to 0.9. Meaning their biases balance out.
The same for 0.2 and 0.8, 0.3 and 0.7, and 0.4 and 0.6; All numbers except 0.5. We do not have a counterbalance for 0.5 between 0 and 1.

To balance rounding 0.5 we balance it with 1.5. We remove 0.5 from 0.5 and add 0.5 to 1.5. Meaning that rounding is just as likely to increase as decrease a random number.

Conclusion

Rounding in Python may seem unusual at first glance, but it’s actually quite useful. Understanding how it works is essential as it can cause a program to behave differently than expected. While it may not have a significant impact in most cases, it’s important to be aware of this behavior to avoid any potential issues.

Do your career a big favor. Join DEV. (The website you're on right now)

It takes one minute, it's free, and is worth it for your career.

Get started

Community matters

Top comments (1)

Collapse
 
sreno77 profile image
Scott Reno

Good info!

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Immerse yourself in a wealth of knowledge with this piece, supported by the inclusive DEV Community—every developer, no matter where they are in their journey, is invited to contribute to our collective wisdom.

A simple “thank you” goes a long way—express your gratitude below in the comments!

Gathering insights enriches our journey on DEV and fortifies our community ties. Did you find this article valuable? Taking a moment to thank the author can have a significant impact.

Okay