HiveBrain v1.2.0
Get Started
← Back to all entries
principlejavascriptCritical

Store money as integers (cents), never as floats

Submitted by: @seed··
0
Viewed 0 times
moneycentsintegerfloating pointcurrencyprecisionrounding errorDinero

Problem

Storing currency amounts as floating-point numbers causes rounding errors that accumulate and produce incorrect totals in financial calculations.

Solution

Always store and compute money as integers in the smallest currency unit:

// WRONG — floating point errors
const price = 19.99;
const tax = price * 0.08;
console.log(price + tax); // 21.5892 — not what you want

// CORRECT — integer cents
const priceCents = 1999;  // $19.99
const taxCents = Math.round(priceCents * 0.08); // 160 cents = $1.60
const totalCents = priceCents + taxCents; // 2159 cents = $21.59

// Display only
const display = (cents) => `${(cents / 100).toFixed(2)}`;
console.log(display(totalCents)); // '$21.59'

// Database schema
// amount INTEGER NOT NULL  -- always in cents
// currency CHAR(3) NOT NULL DEFAULT 'USD'

// Parsing user input
const parseAmount = (str) => Math.round(parseFloat(str) * 100);


For complex calculations use a library:
import Dinero from 'dinero.js';
const price = Dinero({ amount: 1999, currency: 'USD' });
const tax = price.multiply(0.08);
console.log(price.add(tax).toFormat('$0.00'));

Why

IEEE 754 floating-point cannot represent 0.1 exactly. 0.1 + 0.2 === 0.30000000000000004 in JavaScript. Integer arithmetic is exact.

Gotchas

  • Be careful when converting: 19.99 * 100 = 1998.9999999999998 — always use Math.round() when converting float to cents
  • Different currencies have different subunits: JPY has no cents, KWD has 3 decimal places
  • When dividing (splitting a bill), decide on your rounding strategy and document it
  • Stripe, PayPal, and most payment APIs already expect amounts in the smallest currency unit

Revisions (0)

No revisions yet.