Python Near-Zero Comparisons: Define units and tolerance, Check finite input values, Test inside and outside limits

Compare Python Floats Near Zero with an Explicit Absolute Tolerance

Learn why Python math.isclose can reject a tiny value against zero, choose a meaningful absolute tolerance, and test finite-value boundaries.

If Python’s math.isclose(value, 0.0) returns false for a tiny nonzero number, that is not necessarily a bug. The default absolute tolerance is zero. When one side is zero, the usual relative tolerance cannot accept a nonzero difference. Choose a positive absolute tolerance that represents an acceptable difference in your application’s units.

This tutorial is about validating small numerical differences, not rounding a display or silently changing data. A tolerance is an explicit acceptance rule. It must come from the task’s accuracy requirements rather than whichever setting makes an inconvenient test pass.

Understand what the comparison actually measures

The official Python documentation defines closeness using this condition:

abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)

The relative component scales with the larger magnitude of the two inputs. The absolute component supplies a fixed allowance. The function accepts the comparison when the difference fits within the larger allowance, not only when both tests pass.

With zero on one side and a nonzero value on the other, a relative tolerance below one cannot bridge the entire difference. The documentation specifically recommends adding an appropriate positive abs_tol for comparisons against zero. Setting rel_tol=0.0 is useful when your requirement is exclusively a fixed absolute bound.

Run a small boundary demonstration

The following self-contained Python example uses a hypothetical measurement recorded in seconds. The allowed residual is one microsecond. That allowance is invented for this demonstration; it is not a recommendation for timing systems, finance or safety-critical measurements.

import math

limit = 1e-6
print(math.isclose(1e-12, 0.0))
for residual in (5e-7, -5e-7, 2e-6):
    accepted = math.isclose(residual, 0.0, rel_tol=0.0, abs_tol=limit)
    print(residual, accepted)

assert math.isclose(limit, 0.0, rel_tol=0.0, abs_tol=limit)
assert not math.isclose(2 * limit, 0.0, rel_tol=0.0, abs_tol=limit)

The first printed result is false despite the small input. The two residuals with magnitude below the chosen limit pass; the larger positive residual fails. The assertions also demonstrate that the boundary is inclusive. A negative residual is compared by magnitude, not accepted merely because it is numerically less than a positive threshold.

Separate closeness from valid input

For a measurement-validation task, decide whether nonfinite values are allowed before asking whether values are close. Python documents that NaN is not close even to itself, while each infinity is close to itself. Therefore, closeness alone is not a finite-input validator.

import math

def near_zero(value, *, absolute_limit):
    if not math.isfinite(absolute_limit) or absolute_limit < 0:
        raise ValueError("absolute_limit must be finite and nonnegative")
    if not math.isfinite(value):
        return False
    return math.isclose(value, 0.0, rel_tol=0.0, abs_tol=absolute_limit)

assert near_zero(5e-7, absolute_limit=1e-6)
assert near_zero(-5e-7, absolute_limit=1e-6)
assert not near_zero(2e-6, absolute_limit=1e-6)
assert not near_zero(float("nan"), absolute_limit=1e-6)
assert not near_zero(float("inf"), absolute_limit=1e-6)

This helper assumes numeric inputs appropriate for math functions; it is not a general schema validator. It deliberately rejects nonfinite measurements and invalid tolerance settings. It does not parse text, reject every unwanted Python type or repair missing input fields. Keep those concerns separate so failures are understandable.

If the values will later become API data, see rejecting NaN and Infinity in Python JSON before API export. A value passing this comparison does not guarantee that an entire outgoing document meets the receiving API’s contract.

Choose the limit before evaluating real results

Record the unit, expected scale and accepted error before changing code. Converting seconds to milliseconds changes the appropriate absolute tolerance by the same unit conversion. Copying the same numeric tolerance without its unit changes the acceptance rule.

Also ask whether approximate equality is appropriate at all. Identifiers, record counts and exact contractual amounts may require different representations or rules. A close-enough floating-point result is not evidence that an upstream calculation, instrument or business decision is correct.

Review checklist and brief FAQ

  • Test zero, a small positive residual and a small negative residual.
  • Test values just inside, at and outside the chosen bound.
  • Document units and why the tolerance is acceptable.
  • Handle NaN and infinities explicitly when finite data is required.
  • Do not tune tolerances simply to hide unexplained discrepancies.

Does isclose round either input? No. It returns a Boolean comparison result. Should every float comparison use the same limit? No. A fixed error allowance needs context; a threshold suitable for one unit or measurement may be inappropriate for another.

Source: Python’s math documentation, including isclose and isfinite. The examples require only the standard library.

This tutorial is for educational purposes. Test carefully before using any steps in production. The site owner is not responsible for misuse, damage, data loss or production issues.

Leave a Reply

Your email address will not be published. Required fields are marked *