Developer Guides
By Fadhil Abdulla

Floating-Point Money Bugs and Rounding in Code

Why floats break money, how to use integer minor units or decimals, rounding modes, allocating remainders and tests that catch bugs.

Editorial disclosure: Pyalm publishes and maintains the products and free tools discussed on this site. Regulatory statements are linked to primary sources where applicable. No independent professional review is claimed unless a reviewer is explicitly named.

0.1 + 0.2 !== 0.3. Everybody sees this once and forgets it until a customer's total is one fils off. Money is a domain where "nearly right" is a bug.

Why floats fail

Binary floating point (IEEE 754 doubles) can't represent most decimal fractions exactly. 0.1 is stored as a repeating binary fraction, so arithmetic accumulates tiny errors:

0.1 + 0.2            // 0.30000000000000004
1.005 * 100          // 100.49999999999999
(1.005).toFixed(2)   // "1.00" — not "1.01"

Add them up over thousands of invoice lines and you get totals that don't tie to the cent.

Three safe approaches

  1. Integer minor units. Store AED 12.50 as 1250 (fils). Add, subtract and compare integers exactly. Convert to display only at the edge. This is the most common approach.
  2. Decimal types. Use DECIMAL/NUMERIC in the database and a decimal library in code (Java BigDecimal, Python decimal, decimal.js or big.js in JavaScript).
  3. Strings for transport. In JSON, send amounts as strings ("12.50") or integer minor units so no client parses them as floats.

In SQL, use NUMERIC(19,4) or integer columns — never FLOAT or DOUBLE for money.

Currency exponents

Don't hard-code 100. AED, USD, EUR have two decimal places; JPY has zero; KWD, BHD and OMR have three. Keep the currency code with every amount, and look up the exponent.

Rounding modes

Mode Behaviour Where used
Half up 2.5 → 3, 1.5 → 2 Most invoices and tax
Half even ("banker's") 2.5 → 2, 1.5 → 2 Statistical accuracy, some financial systems
Down / truncate Drops the fraction Some fee rules
Up (ceiling) Always up Some tax rules

Check what the tax authority, your bank or your contract requires — and apply it in one place. Note that JavaScript's Math.round rounds half toward +∞ (so -2.5 → -2), and toFixed operates on the binary value, which causes the 1.005 surprise above.

When to round

Round as late as possible in calculations and exactly where a figure is printed or posted. If an invoice line shows a rounded VAT amount, the total must be built from the rounded parts, or customers will find that the numbers don't add up. Decide per line vs per invoice and document it.

Splitting and allocating

Splitting AED 100.00 three ways gives 33.33 × 3 = 99.99. The leftover fils must go somewhere. Use allocation with remainder distribution: compute the base share in minor units (3333), then give the remaining fils one at a time to the first N parts (3334, 3333, 3333). The parts always sum to the total.

function allocate(total, parts) {
  const base = Math.floor(total / parts);
  let remainder = total - base * parts;
  return Array.from({ length: parts }, () => base + (remainder-- > 0 ? 1 : 0));
}
allocate(10000, 3); // [3334, 3333, 3333]

Percentages and VAT

For 5% VAT on 1,999 fils: 1999 × 5 ÷ 100 = 99.95 fils — which has to round to 100 (half up). Do the multiplication on integers first and divide last, with an explicit rounding step. Never compute amount * 0.05 with a float.

Tests that catch money bugs

  • Property tests: the sum of allocated parts equals the total; line totals plus tax equal the invoice total.
  • Golden examples from real invoices, including awkward fractions (x.xx5).
  • Round-trip tests through the database and JSON.
  • Large values and negative amounts (credit notes).
  • Different currency exponents.

Don't forget the accounting

Correct arithmetic is necessary, not sufficient: balanced journals, tax accounts and reconciliation matter too — see building an invoicing system. Try the VAT Calculator to sanity-check results, and use the JSON Formatter to inspect payloads. For raw business books, Pyalm Books does the arithmetic and posting for you, free during beta.

Need a financial feature built right?

Billing, invoicing, reconciliation and reporting features are where precision matters most. See custom software development or talk to Pyalm.

Keep reading

More from Pyalm

Oct 16, 2026

CSV vs JSON: Which to Use and How to Convert

The real differences between CSV and JSON, when each fits, and the conversion traps: leading zeros, dates, encodings and nested data.

Oct 16, 2026

How Text Diff Works and How to Read One

How diff tools find changes with the longest common subsequence, how to read unified diff output, and when line diffs mislead you.

Oct 16, 2026

Markdown Cheat Sheet for Developers

Every Markdown element you actually use (headings, lists, links, code, tables) plus common gotchas, flavour differences and how to preview first.

Oct 16, 2026

SQL Formatting Best Practices With Examples

A practical SQL style guide: keyword case, clause layout, joins, aliases, CTEs, commas and comments, with before-and-after examples.

Oct 16, 2026

JSON to TypeScript Types: Inference and Validation

Turn API responses into TypeScript types, handle optional fields, nulls and unions, and learn why types alone don't validate data at runtime.

Oct 16, 2026

WCAG Colour Contrast Guide: AA vs AAA Ratios

What WCAG contrast ratios mean, the AA and AAA thresholds for text and UI, how the ratio is calculated and how to fix failing colours.

Planning your custom software project?

Purpose-built systems, internal tools, portals, and integrations shaped around how your company actually works. Tell us what you need, and Pyalm will help you scope it.

Discuss your project About Custom software WhatsApp us