Python
floats
floating-point comparison
almost-equality
programming tips

How to compare floats for almost-equality in Python?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Floating-point numbers are approximations, so direct equality checks are often too strict for real programs. In Python, the standard way to test whether two floats are "close enough" is math.isclose.

Why == Often Fails for Floats

Many decimal fractions cannot be represented exactly in binary floating-point. That is why this classic comparison fails:

python
1a = 0.1 + 0.2
2b = 0.3
3
4print(a == b)  # False
5print(a)       # 0.30000000000000004

The numbers are mathematically equal for your business logic, but their in-memory representations differ by a tiny rounding error.

Use math.isclose for Scalar Values

Python's math module provides isclose, which compares numbers using a relative tolerance and an optional absolute tolerance.

python
1import math
2
3a = 0.1 + 0.2
4b = 0.3
5
6print(math.isclose(a, b, rel_tol=1e-9, abs_tol=0.0))  # True

Relative tolerance answers the question "How large is the allowed error compared with the size of these numbers?" That works well when values are not near zero.

Use abs_tol When Comparing Against Zero

Relative tolerance alone is usually not enough when one value is zero or extremely small. In that case, specify an absolute tolerance too.

python
1import math
2
3print(math.isclose(1e-12, 0.0, rel_tol=1e-9, abs_tol=1e-9))  # True
4print(math.isclose(1e-6, 0.0, rel_tol=1e-9, abs_tol=1e-9))   # False

This is one of the most important details in float comparison. If your code compares measurements, residuals, or tiny probabilities against zero, choose abs_tol deliberately.

Choosing a Tolerance

There is no universal tolerance that is correct for every project. The right value depends on the scale of the numbers and the consequences of a false match.

Some examples:

  • financial values should usually avoid binary float entirely and use Decimal
  • geometry code may need a tolerance based on coordinate scale
  • scientific code may use a tolerance derived from the expected measurement error

The important point is that tolerance is part of your domain logic, not just a technical detail.

Arrays and NumPy Values

If you are working with NumPy arrays, use numpy.isclose or numpy.allclose instead of looping manually.

python
1import numpy as np
2
3x = np.array([0.1 + 0.2, 1.0000001])
4y = np.array([0.3, 1.0])
5
6print(np.isclose(x, y))
7print(np.allclose(x, y, rtol=1e-6, atol=1e-9))

The idea is the same, but NumPy applies the comparison element by element across arrays.

Special Values

Be careful with NaN and infinity. NaN is not equal to anything, including itself, and almost-equality checks involving NaN are usually false. Infinity behaves differently again, so do not assume every edge case follows the same tolerance rule.

If your data can contain these values, handle them intentionally before comparing.

When Exact Equality Is Still Fine

Almost-equality is not always necessary. Exact comparison is still correct when:

  • the values are integers stored as floats by convention
  • both values were assigned from the same already-computed result
  • the domain truly requires exact bit-for-bit equality

The problem is not the == operator itself. The problem is using it where rounding error is expected.

Common Pitfalls

The biggest pitfall is picking a tolerance without thinking about scale. A tolerance that is safe for small lab measurements may be dangerously loose for million-dollar totals.

Another common mistake is forgetting abs_tol when comparing to zero. Relative tolerance alone can reject values that are effectively zero for your application.

Also avoid using string formatting as a comparison technique. Rounding both numbers to a printed string may hide real differences and mixes presentation logic with numeric logic.

Summary

  • Use math.isclose instead of == when comparing floats that may differ by rounding error.
  • Set rel_tol for scale-based comparisons and abs_tol when zero is involved.
  • Choose tolerances based on domain requirements, not copied defaults.
  • Use numpy.isclose or numpy.allclose for array data.
  • If you need exact decimal behavior, prefer Decimal over binary floating-point.

Course illustration
Course illustration

All Rights Reserved.