How to compare floats for almost-equality in Python?

2 min read 08-10-2024
How to compare floats for almost-equality in Python?


When working with floating-point numbers in Python (and most programming languages), you may encounter a common problem: due to precision limitations, direct comparisons can often yield unexpected results. For instance, you might expect two values to be equal, but a straightforward comparison might show they are not. This article explores how to compare floats for almost-equality effectively in Python.

Understanding the Problem

When you compare two floats directly using the equality operator ==, you may find that numbers which should be approximately equal are not evaluated as such. This is largely due to how floating-point arithmetic works in binary representation, which can lead to tiny discrepancies.

Original Code Example

Consider the following simple example:

a = 0.1 + 0.2
b = 0.3

print(a == b)  # Output: False

You might expect a and b to be equal, but the result is False. This discrepancy arises because the exact decimal representations of 0.1, 0.2, and 0.3 cannot be represented accurately in binary.

Techniques for Comparing Floats

1. Using Absolute Tolerance

A common way to handle this issue is to compare the absolute difference between the two numbers to a small threshold, often referred to as epsilon.

def almost_equal(a, b, epsilon=1e-10):
    return abs(a - b) < epsilon

a = 0.1 + 0.2
b = 0.3

print(almost_equal(a, b))  # Output: True

In this example, we define an almost_equal function that checks if the absolute difference is smaller than a defined threshold (epsilon). This method works well for cases where you have a known precision requirement.

2. Using Relative Tolerance

In some cases, the absolute difference may not be suitable, particularly when working with very large or very small numbers. Instead, you can use a relative comparison:

def almost_equal(a, b, rel_tol=1e-9):
    return abs(a - b) <= rel_tol * max(abs(a), abs(b))

a = 1e10 + 1
b = 1e10

print(almost_equal(a, b))  # Output: True

Here, rel_tol is a relative tolerance, making the comparison relative to the larger of the two values. This method is particularly useful when dealing with magnitudes of different scales.

3. Using math.isclose()

Python 3.5 introduced a built-in function in the math module called isclose(), which simplifies float comparison with options for both absolute and relative tolerances.

import math

a = 0.1 + 0.2
b = 0.3

print(math.isclose(a, b))  # Output: True

math.isclose() takes two main parameters, rel_tol and abs_tol, and performs the necessary checks to see if two floats are close enough to be considered equal.

Summary

In summary, directly comparing floats in Python can lead to unexpected results due to floating-point precision issues. Using methods such as absolute tolerance, relative tolerance, or the built-in math.isclose() function allows for effective comparisons of floats for almost-equality.

Additional Resources

By following these practices, you can ensure more reliable floating-point comparisons in your Python applications. Always remember to choose the appropriate method based on the context and required precision of your calculations. Happy coding!