我們在 landing page 上放了一個貸款計算器 — 沒有後端、沒有發出請求,訪客輸入四五個數字,答案就立即出現。整個功能只是一個小函式,卻花了兩次嘗試才完成,因為這兩個錯誤在輸出金額之前都看不出來。
陷阱 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 個月。
在這裡操作看看:汽車再融資計算器
順帶一提,決定整個答案的輸入是「結清餘額」— 而你在貸款 App 看到的數字通常不是。請打電話給貸款機構索取結清金額。
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.