DEV Community

Andrew Kwak
Andrew Kwak

Posted on

Most compound interest calculators get contributions wrong

I shipped a daily compound interest calculator last week. The math sounded like a solved problem: A = P(1 + r/n)^(nt), wire it to some inputs, done.

It wasn't, and the interesting bugs weren't in the formula.

The bug most calculators ship

The textbook formula covers a lump sum sitting untouched. The moment you add regular contributions, say $100 every month, you have to decide when each deposit starts earning.

The lazy implementation adds contributions at the end:

// wrong: contributions never compound
const balance = P * Math.pow(1 + r / n, n * t) + monthly * 12 * t;
Enter fullscreen mode Exit fullscreen mode

The correct one compounds each deposit from the day it lands:

// each contribution compounds for its own remaining term
let balance = P * Math.pow(1 + dailyRate, totalDays);
for (let day = 1; day <= totalDays; day++) {
  if (isDepositDay(day)) {
    balance += monthly * Math.pow(1 + dailyRate, totalDays - day);
  }
}
Enter fullscreen mode Exit fullscreen mode

(In production I use the closed-form annuity formula instead of the loop, but the loop version is the one that makes the difference obvious.)

How much does it matter? Take $10,000 at 5%, daily compounding, plus $100/month for ten years:

  • contributions compounded from deposit date: $32,022.28
  • contributions bolted on at the end: $28,486.65

That's $3,535.63 of silent error. I checked several ranking calculators while building this, and more than one ships the second number.

The 360/365 toggle that does nothing

Banks quote "interest compounded on a 360-day basis," so I added a 365/360 day-count toggle, expecting drama.

At the same nominal rate, changing only the exponent basis moves $10,000 over ten years by one cent. The toggle is honest, but advertising it as a feature would be theater.

The thing that actually moves money is the bankers' method: divide the annual rate by 360, then charge interest for all 365 days. That multiplies the effective rate by 365/360, a 1.39% bump, which turns 5% into ~5.07% and $16,486.65 into roughly $16,601. Same label, three orders of magnitude more effect. If you build one of these, model the method, not the toggle.

Rounding will betray your own docs

I wrote the explainer copy with full-precision math: 5% × 365/360 = 5.069444…%, giving $16,601.52.

Then I typed the rounded rate a reader would actually enter (5.0694%) into my own calculator: $16,601.45.

Seven cents apart, and a reader who checks the worked example against the tool concludes one of them is broken. The fix was editorial, not numerical: the page now says "roughly $16,601" and explains why. If your copy quotes numbers your own tool can't reproduce keystroke-for-keystroke, you lose the only thing a calculator page has, which is trust.

URL state: only serialize the diff

First version wrote every input to the query string on every change. Share links looked like:

?p=10000&r=5&c=0&cf=12&n=daily&y=10&b=365
Enter fullscreen mode Exit fullscreen mode

Two problems. Cosmetically it's noise. Practically, a shared link froze every setting, including ones the sender never touched, so recipients opened a calculator configured differently from the page's own documentation (monthly vs daily compounding, in my case, which contradicts the copy right below it).

Now only non-default values serialize:

const qs = Object.entries(state)
  .filter(([k, v]) => v !== DEFAULTS[k])
  .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)
  .join("&");
Enter fullscreen mode Exit fullscreen mode

Untouched calculator gives a clean URL. Change one field and you get ?c=100. Reset it, clean again.

Verify against a second implementation, not your own eyes

Every number above went through a separate closed-form script before shipping: annuity formula, no loops, different code path. The loop implementation and the closed form agreed to the cent ($6,977.00 of pure annuity interest in the test case) before anything went live.

It caught one real discrepancy (the rounding issue above) that eyeballing the UI never would have. For a page whose entire value is "these numbers are right," a reference implementation is the cheapest insurance there is.


The calculator is free and runs client-side: toolmate.io/daily-compound-interest-calculator

Top comments (0)