aboutsummaryrefslogtreecommitdiffstats
path: root/lpd.zig
blob: 943b0d9c9ed4bcc369336fdcd2fce4a1fb469693 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
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 <balance> -p <payment> -r <rate>\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 });
    }
}