Skip to content

Choosing a numeric type

Python gives you four numeric types worth choosing between — int, float, Decimal, and Fraction — and most numeric bugs are really a type-choice bug in disguise. Money stored in a float, a ratio forced through decimals, an exact count drifting because it went through floating point: each is the wrong type quietly doing its best. This essay is a short framework for picking the right one the first time.

The question that decides it: must this be exact?

Numbers in programs fall into two camps. Some are counted or specified exactly — a number of items, a price, a ratio. Others are measured or continuous — a temperature, a coordinate, a probability, a duration. The first camp needs exactness; the second is approximate by its very nature, because the measurement was approximate to begin with.

This single distinction does most of the work:

  • Exact, whole numbersint. It's exact and unbounded, so counts, indices, identifiers, and integer maths never lose precision or overflow.
  • Exact decimal amountsDecimal. Money and anything denominated in decimal units with defined rounding.
  • Exact ratiosFraction. Quantities that are fundamentally fractions and must stay exact.
  • Measured or continuousfloat. Everything else — and it's the majority.

int: the default for whole things

If a quantity is conceptually a whole number, keep it one. Python's int is exact and has no size limit, so it never surprises you. The only trap is /, which always yields a float; use // when you want to stay in integers. Counting, indexing, money-in-pence (some systems store currency as integer minor units precisely to stay exact), bit manipulation — all int.

float: the default for measured things

float is fast, compact, hardware-accelerated, and accurate to about 16 significant digits over an enormous range. For anything that came from a sensor, a calculation in physics or statistics, a screen coordinate, or a percentage, that precision dwarfs the uncertainty already in the data, so the representation error (see how floating point works) is irrelevant. The cost of float is that it's not exact — so the moment a value must be exact, it's the wrong choice. Don't reach for Decimal out of vague nervousness, though: for genuinely measured quantities, float is not a compromise, it's correct.

Decimal: when the decimal digits are the point

Use Decimal when a number is defined in decimal and the exact digits matter: money, tax, invoices, anything with a published rounding rule. Decimal thinks in base 10, so 0.1 is exactly one tenth and a total of pennies stays a total of pennies. It also gives you explicit control over precision and rounding mode, which financial rules often mandate. The price is speed and a little ceremony (build from strings, quantize at the end), but when correctness is measured in pennies that ceremony is the job. See handle money with Decimal.

Fraction: when ratios must stay exact

Fraction is the niche but unbeatable choice when your quantities are genuinely rational and thirds, sevenths, or other non-terminating fractions must remain exact through a chain of arithmetic — exact probabilities, gear ratios, slopes, or teaching maths. It keeps a numerator and denominator, auto-reduced, so ⅓ + ⅓ + ⅓ is exactly 1, which neither float nor Decimal can promise. You convert to float for display or further approximate work at the end.

A decision table

The quantity is… Type Because
a count, index, or id int exact and unbounded
money / a decimal amount Decimal exact in base 10, controllable rounding
an exact ratio (thirds, etc.) Fraction keeps rationals exact
measured, continuous, scientific float fast, ample precision, error irrelevant
a truth value used as 0/1 bool it is an int

The cost of choosing exactness

Exact types aren't free. Decimal and Fraction are considerably slower than float and use more memory, and Fraction's denominators can grow large over long calculations. So the rule isn't "exact is always better" — it's match the type to the quantity. Using Decimal for a temperature is as much a mismatch as using float for a bank balance; one wastes performance, the other risks correctness.

In practice the choice is quick. Ask whether the number must be exact. If it's a whole thing, int; if it's decimal money, Decimal; if it's a ratio that must stay exact, Fraction; and if it's measured, float without apology. Get that right at the point you store the value, and the arithmetic downstream takes care of itself.