Arbitrary-Precision Decimal

What it is

Computers usually store numbers with a fraction as floating point. Floating point is fast, but it cannot hold 0.1 exactly. That is why 0.1 + 0.2 gives 0.30000000000000004 in most languages. For money this is not good enough. A cent that drifts once drifts again on every payment. A decimal type stores numbers in base ten, so 0.1 is exactly 0.1.

The core idea

Keep two things for each number: a whole number of digits and a scale. The scale is how many of those digits sit after the point. 19.99 is the digits 1999 with scale 2. -0.050 is -50 with scale 3. Adding two numbers means giving both the same scale first, then adding the whole numbers. Multiplying means multiplying the whole numbers and adding the scales. Comparing also needs the same scale first. 1.0 and 1.00 are the same value.

Example

1.10 + 2.205: give 1.10 scale 3, so it becomes 1100. Then 1100 + 2205 = 3305, scale 3, which prints as 3.305. 1.5 * 0.25: 15 * 25 = 375, scale 1 + 2 = 3, which prints as 0.375.

Rounding modes

Rounding keeps some digits and may move the kept part one step.

Banks use half_even because rounding every tie up adds a small bias that grows over many payments. A tie is exact only when every dropped digit after the 5 is zero. 0.1251 is not a tie.

Division

Some quotients never end, like 100 / 3. So division always takes a scale and a mode, and rounds the exact answer once. Rounding twice is a classic bug. 0.125125 rounded to three digits is 0.125, which then rounds to 0.12. Rounded once it is 0.13. Dividing by zero is an error, not zero.

Where you meet this

When to choose it: money, prices, tax, interest, or any amount a person will check by hand, where 0.1 + 0.2 must be exactly 0.3 and rounding must follow a stated rule.

When not to: science and graphics, where speed matters more than the last digit and a float's small error is fine.

Common bugs

Keep it fast

Keep numbers in their whole-number form between calls. Build text only in String. Keep powers of ten ready instead of building them one digit at a time.

Learn more

Look up IEEE 754 for floating point and decimal formats. The General Decimal Arithmetic specification explains rounding modes in detail. After this, try the Double-Entry Ledger challenge, where these amounts move between accounts.

Go to the Arbitrary-Precision Decimal challenge