const std = @import("std"); const math = std.math; // Calculates number of months to pay off a balance fn n(b: f64, r: f64, p: f64) f64 { if (r == 0) { return @ceil(b / p); } const i = r / 12; return @ceil(-(math.log(f64, math.e, 1 - (i * b / p))) / math.log(f64, math.e, 1 + i)); } // Calculates lump sum required to pay off a balance in specified time `t` fn l(b: f64, r: f64, p: f64, t: f64) f64 { if (r == 0) { return @max(b - p * t, 0); } const i = r / 12; return b - (p * (1 - math.pow(f64, 1 + i, -t)) / i); } fn u() void { std.debug.print("usage: lpd -b -p -r \n" ++ " -b Principal balance\n" ++ " -p Monthly payment\n" ++ " -r Annual interest rate\n" ++ " -h Show this help message\n", .{}); } pub fn main() !void { const a = try std.process.argsAlloc(std.heap.page_allocator); defer std.process.argsFree(std.heap.page_allocator, a); var b: f64 = 0; var p: f64 = 0; var r: f64 = 0; var i: usize = 1; while (i < a.len) : (i += 1) { const f = a[i]; if (std.mem.eql(u8, f, "-h")) { u(); return; } else if (i + 1 < a.len) { const v = std.fmt.parseFloat(f64, a[i + 1]) catch { u(); return; }; if (std.mem.eql(u8, f, "-b")) { b = v; } else if (std.mem.eql(u8, f, "-p")) { p = v; } else if (std.mem.eql(u8, f, "-r")) { r = v / 100; } else { u(); return; } i += 1; } else { u(); return; } } if (b == 0 or p == 0) { u(); return; } if (p <= r / 12 * b) { std.debug.print("payment must cover interest\n", .{}); return; } const m = n(b, r, p); try std.io.getStdOut().writer().print("{d} remain\n", .{m}); const min = @max(m - 12, 0); var j = m - 1; while (j >= min) : (j -= 1) { const s = l(b, r, p, j); try std.io.getStdOut().writer() .print("pay ${d:.2} for {d}\n", .{ s, j }); } }