等额本息和等额本金:公式推导、舍入误差与还款计划实现

简介: 本文深入解析房贷计算器中易被忽视的“逐期还款计划”,详解等额本息与等额本金的底层计算逻辑:单位统一、零利率处理、舍入策略、尾差校正及总利息累加法。强调代码实现中的实际陷阱与稳健方案,附实战对比工具。

房贷计算器里最容易被低估的部分,不是月供公式,而是“逐期还款计划”。

等额本息和等额本金的总利息差异,表面上看是两个公式的区别;真正写进代码后,还会碰到期数换算、零利率、最后一期尾差,以及金额保留两位小数后“本金、利息、月供加不回来”等问题。

本文以 等额本息与等额本金对比工具 为例,拆解这类工具的计算逻辑。

先统一输入口径

不管是等额本息还是等额本金,输入都应先转换成统一单位:

const principal = amountInWan * 10_000; // 元
const months = years * 12;              // 期
const monthlyRate = annualRate / 12;    // 月利率

这里的 annualRate 应是小数,例如年利率 4% 传入 0.04,而不是 4。

工具页面应明确这一点。用户填写“4”通常表示 4%,程序内部却必须使用 0.04。这类单位错误很隐蔽,算出来的数也“像是真的”,但会大得离谱。

等额本息:每月月供固定,本金占比逐步上升

设:

  • 贷款本金为 P
  • 月利率为 r
  • 总期数为 n
  • 每期月供为 A

等额本息的月供公式为:

[
A = \frac{P \times r \times (1+r)^n}{(1+r)^n - 1}
]

每一期先根据剩余本金计算利息:

[
interestk = balance{k-1} \times r
]

再由固定月供倒推当期归还的本金:

[
principal_k = A - interest_k
]

剩余本金随之更新:

[
balancek = balance{k-1} - principal_k
]

实现时不必单独推导每一期的封闭公式,按还款顺序循环更容易检查:

let balance = principal;

for (let period = 1; period <= months; period += 1) {
   
  const interest = balance * monthlyRate;
  const principalPaid = payment - interest;

  balance -= principalPaid;

  schedule.push({
   
    period,
    payment,
    principal: principalPaid,
    interest,
    balance,
  });
}

以“贷款 100 万元、年利率 4%、期限 30 年”为例,等额本息月供约为 4774.15 元。第一期利息约 3333.33 元,本金只还了约 1440.82 元。前几年看起来还得不少,但剩余本金下降得并不快。

等额本金:每期本金固定,月供逐月下降

等额本金更直接。每期归还的本金固定:

[
principal_k = \frac{P}{n}
]

第 k 期的利息按期初余额计算:

[
interest_k = \left(P - (k-1) \times \frac{P}{n}\right) \times r
]

所以当期月供是:

[
payment_k = principal_k + interest_k
]

对应代码:

const principalPerMonth = principal / months;
let balance = principal;

for (let period = 1; period <= months; period += 1) {
   
  const interest = balance * monthlyRate;
  const payment = principalPerMonth + interest;

  balance -= principalPerMonth;

  schedule.push({
   
    period,
    payment,
    principal: principalPerMonth,
    interest,
    balance: Math.max(0, balance),
  });
}

还是上面的 100 万、4%、30 年案例,等额本金首月约还 6111.11 元,最后一期约 2787.04 元;总利息约 60.17 万元。等额本息的总利息约为 71.87 万元,两者相差约 11.7 万元。

差异不在于某一种方式“更划算”这么简单。等额本金把更多本金放在前期偿还,因此前期月供更高,也更早减少了后续计息的本金基数。

总利息可以用逐期计划汇总,不要只依赖单个公式

等额本金的总利息可以用等差数列快速校验:

[
totalInterest =
P \times r \times \frac{n+1}{2}
]

但实际开发中,仍建议两种方式都从逐期还款计划累加得出总利息:

const totalInterest = schedule.reduce(
  (sum, row) => sum + row.interest,
  0,
);

const totalPayment = schedule.reduce(
  (sum, row) => sum + row.payment,
  0,
);

原因很实际:后续如果要支持提前还款、利率调整、每月服务费,或者某一期有额外还款,单一总公式很快就不够用了;逐期计划仍然可以继续复用。

舍入不要参与核心计算

金额展示通常保留两位小数:

const money = (value: number) =>
  Math.round((value + Number.EPSILON) * 100) / 100;

但有一个常见坑:每期刚算完就把本金、利息、月供全部截断到分,然后再用这些截断值继续算下一期。30 年共 360 期,尾差很容易积累,最后可能出现:

  • 最后一期剩余本金不是 0;
  • 本金合计不是贷款本金;
  • 月供合计不等于本金加利息。

更稳妥的做法是:

  1. 内部使用未舍入的浮点数或整数分进行计算;
  2. 仅在展示每一期时保留两位小数;
  3. 最后一期用剩余本金兜底。
if (period === months || principalPaid > balance) {
   
  principalPaid = balance;
  payment = principalPaid + interest;
}

这样即使前面存在浮点数误差,也能保证最后一期把剩余本金归零。

如果业务要求每一期扣款金额都精确到“分”,还应在生成计划后做一次尾差校正:把前 n - 1 期按规则舍入,最后一期用“应还本金余额 + 当期利息”计算。不能只把最后一期显示成 0,却让累计本金仍对不上。

零利率不是异常数据

月供公式的分母包含:

[
(1+r)^n - 1
]

当 r = 0 时分母为 0,直接套公式会得到 NaN 或 Infinity。零利率虽然少见,但它是合法输入,应该单独处理:

const payment =
  monthlyRate === 0
    ? principal / months
    : (principal * monthlyRate * Math.pow(1 + monthlyRate, months)) /
      (Math.pow(1 + monthlyRate, months) - 1);

对应结果应为:每期归还相同本金,总利息为 0。

对比工具不该只展示“谁省利息”

一个实用的对比页至少要同时呈现:

  • 等额本息的固定月供;
  • 等额本金的首月月供和末月月供;
  • 两种方式的总利息;
  • 两种方式的逐期本金、利息、剩余本金;
  • 首月压力差额。

因为“等额本金少付多少利息”容易理解,“首月多还多少”更接近用户的现金流现实。

我在实现这类页面时,更倾向于先生成两套独立计划,再从计划里派生指标,而不是先算几个汇总数字。这样后续加图表、查第 60 期剩余本金、模拟提前还款,都不需要重写底层逻辑。

可以直接使用 等额本息与等额本金对比工具,在同一本金、利率和期限下查看两套还款计划。实际贷款以合同、放款日、计息规则和银行结算结果为准。

相关文章
|
10月前
|
移动开发 小程序 前端开发
小程序开发平台有哪些?哪个好
小程序项目落地的第一步,也是最关键的一步,就是开发平台的精准选型。它不仅影响项目的开发周期与成本投入,更直接决定了后续业务的适配度和运营上限。企业需结合自身技术能力、预算区间、功能需求等核心要素综合权衡。本文将对主流小程序开发平台进行分类拆解,通过详细对比和场景化推荐,帮助不同类型的企业找到最契合的解决方案。
874 9
|
机器学习/深度学习 人工智能 达摩院
10万亿!达摩院发布全球最大AI预训练模型M6
今天,阿里巴巴达摩院公布多模态大模型M6最新进展,其参数已从万亿跃迁至10万亿,成为全球最大的AI预训练模型。
9613 0
10万亿!达摩院发布全球最大AI预训练模型M6
|
19天前
|
存储 人工智能 弹性计算
需要一次购买多个阿里云AI产品怎么买更优惠?精选AI 产品组合购,无需凑单直接省
阿里云推出组合购玩法,以Token Plan为模型算力底座,围绕部署AI Agent、AI编程、AI自选、AI建站、AI通用入门五大场景,将编程入口、落地环境、域名备案等能力打包成精选套餐。如AI Agent组合低至68元起,AI编程全能包98元起,AI建站套餐15元/月起并赠.CN域名与备案服务码,通用入门节省计划首购10元起。一次下单即选即用,组合价通常低于单买,无需跨页凑单。
|
22天前
|
存储 运维 安全
电商平台客户数据泄露衍生钓鱼风险及治理路径研究
本文以荷兰DA电商数据泄露事件为案例,剖析非金融类个人信息(如姓名、地址、订单记录)遭未授权访问后,如何被用于定向网络钓鱼诈骗。指出“访问发生但拷贝不确定”的灰色风险,揭示企业应急响应、用户预警与跨部门协同短板,并提出覆盖事前防护、事中响应、事后防控的综合治理路径。(239字)
62 1
|
23天前
|
人工智能 自然语言处理 安全
阿里云千问办公 QwenWork详细介绍:产品核心能力、典型场景、价格及常见问题解答
本文详解阿里云千问办公QwenWork企业级AI办公智能体平台,平台深度打通钉钉生态,支持通过自然语言生成标准办公文档、全栈免部署网页,配套海量专业技能与电商数据源接入能力,覆盖桌面端、网页端与钉钉端,198元/席/月起的企业版支持年费限时积分加赠,全方位助力企业全办公场景提效。
|
6月前
|
开发框架 Java 数据库连接
一张图讲完Java 30年发展史,看完彻底搞懂版本演进
这篇Java版本演进指南,用一天时间理清30年发展脉络:从JDK 1.0“一次编写,到处运行”,到JDK 8函数式革命(Lambda/Stream),再到JDK 17/21 LTS新标配(var/record/虚拟线程)。帮你告别版本困惑,读懂面试考点,选对生产版本。
一张图讲完Java 30年发展史,看完彻底搞懂版本演进
|
机器学习/深度学习 人工智能 测试技术
【自定义插件系列】0基础在阿里云百炼上玩转大模型自定义插件
本文介绍了如何在阿里云百炼平台上创建大模型自定义插件,以增强AI模型功能或适配特定需求。通过编程接口(API)或框架设计外部扩展模块,开发者可在不修改底层参数的情况下扩展模型能力。文章以万相文生图V2版模型为例,详细说明了创建自定义插件的五个步骤:新建插件、创建工具、测试工具、复制第二个工具及最终测试发布。同时,提供了官方文档参考链接和具体参数设置指导,帮助用户轻松实现插件开发与应用,推动AI技术在各行业的广泛应用。
2553 0
|
开发者
【软件开发规范三】【软件版本命名规范】
软件版本号有四部分组成,第一部分为主版本号,第二部分为次版本号,第三部分为修订版,第四部分为日期版本号加希腊字母版本号,希腊字母版本号共有五种,分别为base、alpha、beta、RC、release
1986 1
【软件开发规范三】【软件版本命名规范】
|
安全 Android开发
【Android 逆向】Android 中常用的 so 动态库 ( libm.so 数学函数动态库 | liblog.so 日志模块动态库 | libselinux.so 安全模块动态库 )
【Android 逆向】Android 中常用的 so 动态库 ( libm.so 数学函数动态库 | liblog.so 日志模块动态库 | libselinux.so 安全模块动态库 )
1222 0
【Android 逆向】Android 中常用的 so 动态库 ( libm.so 数学函数动态库 | liblog.so 日志模块动态库 | libselinux.so 安全模块动态库 )
|
监控 JavaScript 前端开发
Vue3组合式函数(监听DOM尺寸 useResizeObserver)
本文介绍如何使用 `ResizeObserver` API 编写 Vue3 的通用组合式函数 `useResizeObserver`,该函数可方便地观察一个或多个元素的尺寸变化,并执行指定回调。`ResizeObserver` 接口用于监控 `Element` 或 `SVGElement` 的尺寸变化,避免了无限回调循环问题。
1525 0
Vue3组合式函数(监听DOM尺寸 useResizeObserver)

热门文章

最新文章