fractions: limit_denominator() Default Silently Approximates (tested)
Fraction.limit_denominator() is often reached for as a generic "simplify this fraction" call, especially when called with no arguments. We measured what the no-argument call actually does, and it has a hidden default denominator cap that silently discards precision on exact fractions that exceed it -- no error, no warning.
1. limit_denominator() has a default max_denominator of exactly 1,000,000
from fractions import Fraction
import inspect
print(inspect.signature(Fraction.limit_denominator))
(self, max_denominator=1000000)
Measured: the method's signature shows max_denominator=1000000 as the default -- calling f.limit_denominator() with no argument is exactly equivalent to f.limit_denominator(1_000_000), which is easy to miss since nothing in a typical call site mentions the number.
2. An exact Fraction with a denominator past one million gets silently replaced
from fractions import Fraction
f = Fraction(1, 3_000_000)
print("original:", f)
print("limit_denominator():", f.limit_denominator())
print("still equal?", f == f.limit_denominator())
original: 1/3000000
limit_denominator(): 0
still equal? False
Measured: Fraction(1, 3_000_000) is a perfectly exact, already-reduced fraction -- there's nothing to "simplify." Calling limit_denominator() on it with no argument doesn't leave it unchanged; it returns 0, the closest fraction with a denominator under a million to a value this small. No exception, no warning -- just a silently different number.
3. A less extreme case shows the same silent substitution, just smaller
from fractions import Fraction
f = Fraction(22, 7) * Fraction(1, 500_000)
print("original:", f)
print("limit_denominator():", f.limit_denominator())
original: 11/1750000
limit_denominator(): 6/954545
Measured: 11/1750000 (denominator over the 1,000,000 default) gets replaced by the nearest fraction with a denominator under a million, 6/954545 -- a different, merely approximate value, with no indication anything was lossy. For comparison, a Fraction whose denominator naturally stays under a million (e.g. the sum of several small unit fractions) passes through limit_denominator() completely unchanged, which is likely why the no-argument form feels safe in testing: small examples happen not to trigger it. Any code built or measured with small denominators, then later fed real values with denominators that grow past a million (repeated fraction arithmetic, parts-per-million rates, high-precision ratios from Decimal conversions), will see limit_denominator() silently start approximating where it previously passed values through unchanged. If the intent is "simplify only if needed," compare the result against the original first, or pass an explicit max_denominator sized to the actual precision required.
Frequently asked questions
What is the default max_denominator for Fraction.limit_denominator()?
1,000,000 -- we confirmed via inspect.signature(Fraction.limit_denominator) that calling it with no argument is equivalent to limit_denominator(1_000_000).
Does limit_denominator() leave an already-exact Fraction unchanged?
Only if its denominator is under the (default or given) max_denominator. We measured Fraction(1, 3_000_000).limit_denominator() -- called with no argument -- returning 0 instead of the original value, with no exception or warning, because 3,000,000 exceeds the default cap of 1,000,000.
Why did limit_denominator() change my Fraction's value unexpectedly?
Its no-argument form caps the denominator at 1,000,000 by default. If your Fraction's denominator is naturally larger than that -- from repeated arithmetic, parts-per-million rates, or a Decimal-to-Fraction conversion -- limit_denominator() silently approximates it to the nearest fraction under that cap instead of leaving it alone.
How do I call limit_denominator() without silently losing precision?
Pass an explicit max_denominator sized to the precision you actually need, or compare the result to the original Fraction with == before relying on it, since the no-argument call (max_denominator=1_000_000) gives no indication when it has changed the value.
Written with AI assistance. Measured on 2026-10-04 with Python 3.13.5's built-in fractions module: called limit_denominator() with no argument on exact Fractions whose denominator is larger than one million, and inspected the method's default parameter value directly. PlainHeaders is our extension; Python's fractions module is built in.