A Loan Calculator With 元利均等 vs 元金均等 and Prepayment Simulation
Japanese mortgages let you choose between 元利均等 (equal total monthly payment) and 元金均等 (equal principal portion). The first has a constant monthly amount; the second has a decreasing amount as interest falls with the balance. The total interest differs significantly — equal principal pays less interest overall but has higher initial payments. A calculator that shows both side by side clarifies the trade-off.
Mortgage calculators are everywhere but most only support the equal-installment method. Equal-principal is less common outside Japan but is the standard choice for people who can afford larger early payments to save interest.
🔗 Live demo: https://sen.ltd/portfolio/loan-calc/
📦 GitHub: https://github.com/sen-ltd/loan-calc
Features:
- Two payment methods: equal installment vs equal principal
- Monthly payment + total interest + total paid
- Full amortization schedule
- Prepayment simulation (extra monthly → new term + interest saved)
- Principal vs interest stacked bar chart
- Japanese / English UI (Japanese mortgage focus)
- Zero dependencies, 39 tests
The standard amortization formula
For equal monthly payments on a fixed-rate loan:
export function monthlyPayment(principal, apr, months) {
const r = apr / 12 / 100; // monthly rate
if (r === 0) return principal / months; // zero-interest edge case
return principal * r / (1 - Math.pow(1 + r, -months));
}
This is the classic annuity formula. The payment covers interest on the current balance plus a portion of principal. Early payments are mostly interest; late payments are mostly principal.
A $100,000 loan at 5% over 30 years:
- Monthly payment: $536.82
- Total paid: $193,256
- Total interest: $93,256
The borrower pays almost as much interest as principal over the full term. At higher rates or longer terms, interest can exceed principal.
元金均等: equal principal
In equal-principal, the principal portion is fixed and the interest portion decreases each month:
function equalPrincipalSchedule(principal, apr, months) {
const r = apr / 12 / 100;
const principalPortion = principal / months;
const schedule = [];
let balance = principal;
for (let m = 1; m <= months; m++) {
const interestPortion = balance * r;
const payment = principalPortion + interestPortion;
balance -= principalPortion;
schedule.push({ month: m, payment, principalPaid: principalPortion, interestPaid: interestPortion, balance: Math.max(0, balance) });
}
return schedule;
}
First payment is largest (full interest on full principal + fixed principal). Each subsequent payment is smaller because interest decreases with the shrinking balance.
For the same $100,000 / 5% / 30 year loan:
- First payment: $694.44 ($416.67 interest + $277.78 principal)
- Last payment: $278.94 ($1.16 interest + $277.78 principal)
- Total interest: $75,208 (vs $93,256 for equal installment — $18,048 savings)
The trade-off: you pay more in the early years. If your income is expected to grow, equal-installment might fit your budget better. If you can afford the early burden, equal-principal saves money.
Prepayment simulation
Paying extra each month shortens the loan. How much extra saves how much interest?
export function earlyPayoff(schedule, extraMonthly) {
const r = schedule[0].interestPaid / getOriginalPrincipal(schedule);
let balance = getOriginalPrincipal(schedule);
const monthlyBase = schedule[0].payment;
const monthlyWithExtra = monthlyBase + extraMonthly;
let newMonths = 0;
let newTotalInterest = 0;
while (balance > 0) {
const interest = balance * r;
const principal = Math.min(monthlyWithExtra - interest, balance);
newMonths++;
newTotalInterest += interest;
balance -= principal;
}
const originalInterest = schedule.reduce((sum, row) => sum + row.interestPaid, 0);
return {
newTerm: newMonths,
interestSaved: originalInterest - newTotalInterest,
};
}
The loop advances month by month until the balance is paid off. Extra payments compound: each $100 extra today reduces the balance, which reduces the interest charged next month, which lets more of the next payment go to principal, which reduces the balance further.
For a $100k / 5% / 30-year loan with $100/month extra:
- Original term: 360 months (30 years)
- New term: ~264 months (22 years)
- Interest saved: ~$31,000
Zero-interest edge case
Fun fact: monthlyPayment has a division by zero when apr=0:
// principal * r / (1 - (1 + r)^-n)
// r = 0 → 0 / (1 - 1) = 0 / 0
Handle it explicitly: if interest is 0, the monthly payment is just principal / months. The math still works but JavaScript gives NaN for the formula, so an explicit branch keeps the output clean.
Series
This is entry #98 in my 100+ public portfolio series.
- 📦 Repo: https://github.com/sen-ltd/loan-calc
- 🌐 Live: https://sen.ltd/portfolio/loan-calc/
- 🏢 Company: https://sen.ltd/

Top comments (0)