code wiki / (root) / nx_debt_gate.nx

nx_debt_gate.nx source

↩ module page · 85 lines · 4226 B

1// nx_debt_gate.nx -- R4 GATE: proves debt amortization is bit-exact, detects the minimum-payment trap, 2// and that avalanche pays LESS total interest than snowball (measured, not asserted by faith). 3// 4// EXACT ANCHORS (hand-computed, banker's rounding, 1% monthly = 12% APR): 5// $1,000 @ 12%, pay $2,000 -> 1 month, interest $10.00 (round(1000.00*0.01)=1000c) 6// $1,000 @ 12%, pay $100 -> 11 months, interest $58.98 (5898c) -- full schedule summed by hand 7// $300 @ 0%, pay $100 -> 3 months, interest $0 8// $10,000 @ 24%, pay $100 -> -1 TRAP (interest $200 > payment $100; never amortizes) 9// MEASURED: A=$10,000@24% min$200 + B=$2,000@6% min$50, budget $500/mo. Avalanche kills the 24% debt 10// first; snowball kills the small $2,000 debt first. Both pay off; avalanche pays less interest. 11// Exits 0 iff ALL pass. license_tier: ORIGINAL 12import "nx_syscalls.nx" 13import "nx_money.nx" 14import "nx_debt_payoff.nx" 15 16func g_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 17func g_putn(v: i64) -> i64 { 18 if v == 0 { sys_write(1, "0" as *u8, 1); return 0 } 19 var m: i64 = v 20 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m } 21 let d: *u8 = sys_mmap(24); var k: i64 = 0 22 while m > 0 { d[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 23 var j: i64 = k - 1 24 while j >= 0 { sys_write(1, ((d as i64)+j) as *u8, 1); j = j - 1 } 25 return 0 26} 27func chk(name: *u8, got: i64, want: i64, st: *i64) -> i64 { 28 if got == want { st[0] = st[0] + 1; g_puts(" PASS "); g_puts(name); g_puts("\n") } 29 else { st[1] = st[1] + 1; g_puts(" FAIL "); g_puts(name); g_puts(" got="); g_putn(got); g_puts(" want="); g_putn(want); g_puts("\n") } 30 return 0 31} 32 33func main() -> i64 { 34 let st: *i64 = sys_mmap(16) as *i64 35 st[0] = 0; st[1] = 0 36 37 let rate12: i64 = mny_rate_from_pct(12, 1) 38 let rate24: i64 = mny_rate_from_pct(24, 1) 39 let rate6: i64 = mny_rate_from_pct(6, 1) 40 let oi: *i64 = sys_mmap(16) as *i64 41 42 // exact single-loan anchors 43 chk("payoff $1000@12% pay$2000 = 1 month", dbt_payoff_months(100000, rate12, 200000, oi), 1, st) 44 chk(" 1-month interest = 1000c ($10.00)", oi[0], 1000, st) 45 chk("payoff $1000@12% pay$100 = 11 months", dbt_payoff_months(100000, rate12, 10000, oi), 11, st) 46 chk(" 11-month total interest = 5898c ($58.98)", oi[0], 5898, st) 47 chk("payoff $300@0% pay$100 = 3 months", dbt_payoff_months(30000, 0, 10000, oi), 3, st) 48 chk(" zero-rate interest = 0", oi[0], 0, st) 49 chk("MIN-PAYMENT TRAP $10k@24% pay$100 = -1", dbt_payoff_months(1000000, rate24, 10000, oi), 0 - 1, st) 50 51 // avalanche vs snowball 52 let bal: *i64 = sys_mmap(8 * 2) as *i64 53 let apr: *i64 = sys_mmap(8 * 2) as *i64 54 let minp: *i64 = sys_mmap(8 * 2) as *i64 55 bal[0] = 1000000; apr[0] = rate24; minp[0] = 20000 56 bal[1] = 200000; apr[1] = rate6; minp[1] = 5000 57 let avi: *i64 = sys_mmap(16) as *i64 58 let sni: *i64 = sys_mmap(16) as *i64 59 let avm: i64 = dbt_strategy(bal, apr, minp, 2, 50000, 0, avi) 60 let snm: i64 = dbt_strategy(bal, apr, minp, 2, 50000, 1, sni) 61 62 g_puts(" [info] avalanche: months="); g_putn(avm); g_puts(" interest_cents="); g_putn(avi[0]); g_puts("\n") 63 g_puts(" [info] snowball : months="); g_putn(snm); g_puts(" interest_cents="); g_putn(sni[0]); g_puts("\n") 64 65 var avok: i64 = 0 66 if avm > 0 { avok = 1 } 67 chk("avalanche pays off (months>0)", avok, 1, st) 68 var snok: i64 = 0 69 if snm > 0 { snok = 1 } 70 chk("snowball pays off (months>0)", snok, 1, st) 71 var saves: i64 = 0 72 if avi[0] < sni[0] { saves = 1 } 73 chk("MEASURED: avalanche interest < snowball interest", saves, 1, st) 74 75 // print the measured savings 76 g_puts(" [info] avalanche saves interest_cents="); g_putn(sni[0] - avi[0]); g_puts("\n") 77 78 // under-funded budget (< sum of minimums $250) must be rejected, not loop forever 79 chk("budget $100 < minimums $250 -> rejected (-1)", dbt_strategy(bal, apr, minp, 2, 10000, 0, avi), 0 - 1, st) 80 81 g_puts("nx_debt_gate: PASS="); g_putn(st[0]); g_puts(" FAIL="); g_putn(st[1]); g_puts("\n") 82 if st[1] == 0 { g_puts("R4 nx_debt: GREEN\n"); return 0 } 83 g_puts("R4 nx_debt: RED\n") 84 return 1 85}