Should you use a float for money? Not as the authoritative representation when the amount must be stored or calculated exactly. Binary floating-point cannot represent many decimal fractions exactly. Use decimal arithmetic or integer minor units, then choose the precision, rounding rule and display format explicitly.
Why is floating-point risky for money?
Most familiar currency amounts are written in base 10, but a computer’s binary floating-point format represents numbers in base 2. Many decimal fractions therefore have no exact binary representation. A value that looks like a simple decimal can be stored as a nearby approximation, and arithmetic operates on that stored value.
This is not a defect unique to one language. PostgreSQL documents real and double precision as inexact types, and MDN describes JavaScript’s Number as IEEE 754 double-precision binary floating point. Floating-point remains useful for approximate measurements and calculations where small representation errors are acceptable; it is a poor default for authoritative monetary amounts that require exact decimal handling.
Keep four decisions separate: how input is represented, how arithmetic precision is controlled, when and how a result is rounded, and how the final value is formatted for display. Choosing a decimal type addresses representation, but does not by itself settle the other decisions.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errors#1 Best Overall
Which approach should you choose?
| Approach | Good fit | Main constraint |
|---|---|---|
| Integer minor units | Amounts with one known, fixed scale and arithmetic that stays at that scale. | Scale must be known and carried with the value. Fractional rates, division and currencies or business units with different scales need additional rules. |
| Decimal arithmetic | Amounts and intermediate calculations that need decimal quantities, including calculations involving fractional rates. | Precision, rounding mode and rounding points still need to be configured and documented. |
| Binary floating point | Approximate measurements and calculations where binary rounding error is acceptable. | Many decimal fractions are inexact, so it is risky as the authoritative representation for exact monetary values. |
Choose by checking whether input and storage must be exact, whether intermediate values can be fractional, what scale and range the domain permits, where rounding belongs, how values cross APIs, and whether database portability or performance changes the trade-off. Neither “always store cents” nor “use decimals everywhere” is a complete monetary policy.
How do you do decimal arithmetic in Python?
Use decimal.Decimal and construct values from decimal text. For example:
from decimal import Decimal
price = Decimal("19.99")
quantity = 3
subtotal = price * quantity
Decimal("19.99") preserves the decimal input. By contrast, Decimal(19.99) converts the float’s existing binary approximation; it does not recover the decimal value the programmer intended. The Python 3.11 decimal documentation explains that decimal numbers can be represented exactly.
Rank #2
Configure precision and rounding for the calculation
Decimal arithmetic uses a context. Its precision, rounding mode and traps affect how operations behave. Decide these deliberately for the application rather than assuming the type supplies a complete policy. In particular, do not round every intermediate result to two decimal places simply because a displayed amount commonly has two places.
Quantize at a chosen boundary when the domain requires a particular scale—for example, when finalizing an amount for a transaction or another defined business step. Select the quantization target and rounding mode from the applicable business rules; there is no universal currency scale or rounding mode established by the language documentation.
Why does JavaScript money arithmetic lose precision?
JavaScript’s ordinary numeric type is Number, an IEEE 754 binary64 value. A literal that looks like an integer is still a Number, and the type has a finite exact-integer range. MDN Web Docs gives that range as −(253−1) through +(253−1); values outside it are not all exactly representable as integers.
Use scaled integers for a genuinely fixed scale
If the application has a known scale and can keep the amount within the chosen range, represent the amount in integer minor units. BigInt supports integer arithmetic beyond Number’s safe-integer limit:
const unitPriceMinor = 1999n;
const quantity = 3n;
const totalMinor = unitPriceMinor * quantity; // 5997n
Here, the application must define what one minor unit means; the code does not infer a currency or scale. Check range limits if using ordinary Number integers, and keep the scale associated with the value. JavaScript does not implicitly mix BigInt and Number, and integer storage does not decide how to round division or fractional-rate calculations.
Recommended Free Tools
Use decimal arithmetic for fractional intermediates
For rates, fractional intermediate calculations or multiple scales, use a vetted decimal arithmetic library and review its precision, rounding and serialization behavior. The TC39 Decimal proposal repository provides context for the problem and proposal; it does not establish a built-in JavaScript Decimal type you can rely on.
Which PostgreSQL type should store money?
Prefer numeric(p,s) when exact decimal storage is required
PostgreSQL recommends numeric (also called decimal) when exact storage and calculations are required, such as for monetary amounts. Choose precision and scale to cover the domain: in numeric(p,s), p is the total number of digits and s is the number after the decimal point. For example, numeric(12,2) allows up to twelve total digits, with two after the decimal point; it is an example configuration, not a universal choice for every currency or application.
PostgreSQL says numeric calculations are exact where possible, though they may be slower than integer or floating-point calculations. Its PostgreSQL 15 documentation specifies a maximum of 131072 digits before and 16383 digits after the decimal point for unconstrained numeric. Those are type limits, not sensible defaults for a monetary column.
Preserve the original decimal input when writing to the database. Sending a float and storing its value in an exact decimal column does not restore the decimal input that was lost when it became an approximation.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Best Value
Use money only when its behavior suits the application
PostgreSQL’s money type stores amounts at a fixed fractional precision determined by lc_monetary, and its output formatting depends on locale. That coupling can complicate portability and presentation. If the application needs explicit control of decimal scale or locale-independent output, numeric(p,s) is generally easier to reason about.
Where should rounding happen?
Rounding is a domain rule, not an automatic consequence of picking a numeric type. Define the scale and rounding mode, and specify the point in the calculation at which rounding occurs. Rounding each line, each intermediate operation, or only a final total can produce different results.
- Document the scale required for stored values and for each relevant calculation.
- Specify the rounding mode for each business operation that requires rounding.
- Apply rounding at a named boundary instead of relying on an incidental language, database or display default.
- Test boundary cases, including values exactly between two representable rounded results.
Python’s Decimal context exposes precision and rounding configuration, but neither it nor PostgreSQL’s numeric type determines every business or jurisdictional rule. The technical documentation covered here does not establish which rule applies to a particular transaction; that must come from the application’s requirements.
How should money move through an API and into storage?
Keep the representation and scale explicit across system boundaries. For example, a fixed-scale integer should not travel as an unlabeled number whose unit a receiving service must guess. Decimal values should cross boundaries in a representation that preserves their decimal meaning, and the database write path should not convert them through binary floating point.
- Define the amount’s scale and range at the API boundary.
- Validate incoming values before arithmetic or storage; reject values that exceed the supported scale or range unless a documented rule says how to handle them.
- Choose serialization and database-driver behavior that preserves the intended decimal value rather than silently converting it to a float.
- Format for display separately, using the appropriate locale and currency presentation rules without treating formatted text as the underlying amount.
These checks matter even when the database column is exact: end-to-end behavior depends on the value’s path through parsing, application arithmetic, serialization and persistence.
Quick Recap
Implementation checklist
- Define the domain. Decide which amounts, scales, ranges and fractional calculations the application must support.
- Choose the representation. Use integer minor units for a fixed-scale case that stays within range, or decimal arithmetic when decimal fractional intermediates are needed.
- Preserve input. In Python, construct
Decimalfrom text; in JavaScript, avoid converting monetary input throughNumberif exact decimal input must be retained; in PostgreSQL, avoid passing a float and expectingnumericto reconstruct the original decimal. - Write the rounding policy down. Name the rounding mode, scale and calculation boundary for each operation that requires rounding.
- Set the database type. Choose a suitable
numeric(p,s)range where PostgreSQL exact decimal storage is required, and considermoneyonly with its locale and fixed-scale behavior in view. - Test the whole path. Verify input, arithmetic, rounding, serialization, database storage and display with representative values and boundary cases.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




