float.as_integer_ratio()
The clearest demonstration of what binary floats really hold. The denominator is always a power of two, which is exactly why 0.1 cannot be a tenth.
Demo
Halves, quarters and whole numbers give the small tidy fractions you would expect, because those values fit binary exactly. Then look at 0.1: the answer is 3602879701896397 over 36028797018963968. That enormous pair is not a bug — it is the closest a double can get to a tenth, and it is what every calculation using 0.1 is really working with. The denominator is always a power of two, which is the whole story of binary floating point.
Common patterns
from fractions import Fraction exact = Fraction(*x.as_integer_ratio())
an, ad = a.as_integer_ratio() bn, bd = b.as_integer_ratio() equal = an * bd == bn * ad
print(value.as_integer_ratio())
Examples
Pitfalls
(0.1).as_integer_ratio()
from fractions import Fraction Fraction('0.1')
float('inf').as_integer_ratio()
import math if math.isfinite(x): n, d = x.as_integer_ratio()
(1 / 3).as_integer_ratio()
from fractions import Fraction Fraction(1, 3)
When to use
- Converting a float to an exact Fraction
- Explaining or debugging floating-point discrepancies
- Exact comparison or summation without rounding error
- Teaching what binary floats actually store
- You want the decimal you typed → Fraction(str) or decimal.Decimal
- You know the value is an int → int.as_integer_ratio always gives (n, 1)
- Values may be inf or nan → check with math.isfinite first
Notes
FAQ
Because a tenth cannot be written as a finite sum of powers of two, any more than a third can be written as a finite decimal. The double stores the nearest value it can, and this method reports that value honestly.
(0.1).as_integer_ratio() # (3602879701896397, 36028797018963968)