我们在落地页上放了一个贷款计算器——没有后端,没有请求,访客输入四五个数字,答案便立即出现。整个功能就是一个小函数。但我们仍然尝试了两次,因为两个 bug 在输出变成金额之前都看不出来。
陷阱 1:PMT 在 0% 利率时除零
Excel 的 PMT(rate, nper, pv, fv, type) 是一个封闭形式的年金支付公式:
function pmt(rate, nper, pv, fv, type) {
if (nper === 0) return 0;
if (rate === 0) return -(pv + fv) / nper; // <- the branch people forget
const f = Math.pow(1 + rate, nper);
return -(pv * f + fv) * rate / ((f - 1) * (1 + rate * type));
}
Enter fullscreen mode Exit fullscreen mode
如果省略 rate === 0 这行,通用公式会在分母处得到 (f - 1) === 0,因此 0% 促销贷款——经销商广告的典型案例——会返回 Infinity 或 NaN。Excel 包含这个分支。如果你只照搬金融教科书的代数公式,就不会有这个分支。
另一个细节是符号。 pmt 对正的现值返回负数,因为 Excel 把钱从你手中流出建模。如果你把余额作为 -balance 传入,就能得到正的付款额,其余的算术也就顺理成章了。
陷阱 2:Excel 的 ROUND 与 JavaScript 的 Math.round 不一致
JavaScript 中的 Math.round 是向正无穷方向的“五入”: Math.round(-2.5) === -2。而 Excel 的 ROUND 是“远离零”的五入: ROUND(-2.5, 0) 的结果是 -3。在一个显示储蓄数字的页面上,这会造成浏览器与用户下载的电子表格之间存在一分钱的差异——而一分钱就足以让有人认为其中之一出错了。
function excelRound(x, digits) {
const m = Math.pow(10, digits), v = x * m;
const a = Math.abs(v), fl = Math.floor(a);
const r = ((a - fl) >= 0.5 ? fl + 1 : fl) * (v < 0 ? -1 : 1);
return r / m;
}
Enter fullscreen mode Exit fullscreen mode
为什么要追求一致性
因为电子表格就是产品,而页面只是演示。如果两者相差一分钱,演示就告诉访客不要相信这个产品。
在线版本是一个汽车再融资计算器。它在页面中运行了电子表格 9 个输入中的 5 个和 6 个结果中的 2 个,使用相同的公式——你输入的数字永远不会离开浏览器。即使你不下载任何东西,两个输出也值得一看:月供实际降低了多少,以及结账费用需要多少个月才能收回。在默认数字下,这是 80.24 美元和 2.3 个月。
在这里试用:汽车再融资计算器
顺便说一句,决定整个答案的输入是还款余额——而你贷款人应用里显示的数字通常不是这个。打电话问一下还款余额。
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.