nx_amort_lib.nx
buildroot/runtime/nx_amort_lib.nx
about
nx_amort_lib.nx -- LOAN AMORTIZATION with exact penny allocation. Integer-exact, conservation-proven.
The companion to nx_fin_finance (which ranks a loan's TRUE cost): this produces the actual schedule. The
hard part is not the payment formula -- it is the PENNY: a level payment rarely divides the balance evenly,
and naive amortizers leave a residual cent on the last payment or, worse, create one. Here the schedule is
CONSERVATION-EXACT by construction -- sum of every month's principal reduction == the original principal,
and the final payment is computed to clear the balance to EXACTLY ZERO (remaining balance + its last
month's interest), never a lingering or invented cent.
*THE LEVEL PAYMENT IS FOUND BY INTEGER BISECTION, not the pow((1+r),N) closed form (which needs floats and
rounds unpredictably): the remaining balance after N payments is monotone-decreasing in the payment, so we
bisect for the SMALLEST integer payment that clears the loan in exactly N months. Same technique as the
bond YTM. FAIL-CLOSED: non-positive principal/term or a negative rate returns AMORT_BAD -- no schedule is
produced on nonsense input.
Money is minor units (cents); rate is annual basis points; monthly interest = balance * annual_bp / 120000
(=/12/10000), truncated down (borrower-favorable, absorbed by the final payment). SCALE ENVELOPE: balance
up to ~9e14/annual_bp fits i64. license_tier: ORIGINAL No hw writes (Rule 26). LIB.
dependencies 0 imports · 2 importers
imports: none
imported by: nx_amort_gate.nxnx_finance_svc.nx
structs
| none |
consts
| 20 | const AMORT_BP_MONTH_DIV: i64 = 120000 // annual bp -> monthly fraction denominator (12 * 10000) |
| 21 | const AMORT_BAD: i64 = 0 - 2000000002 // invalid input |
functions
| 24 | func amort_monthly_interest(balance: i64, annual_bp: i64) -> i64 |
| 30 | func amort_balance_after(principal: i64, annual_bp: i64, payment: i64, months: i64) -> i64 |
| 45 | func amort_level_payment(principal: i64, annual_bp: i64, term_months: i64) -> i64 |
| 62 | func amort_final_payment(principal: i64, annual_bp: i64, term_months: i64) -> i64 called by 3: mainamort_total_interestfin_amort_schedule calls 2: amort_level_paymentamort_balance_after |
| 72 | func amort_principal_sum(principal: i64, annual_bp: i64, term_months: i64) -> i64 |
| 92 | func amort_total_interest(principal: i64, annual_bp: i64, term_months: i64) -> i64 |