]>
git.scottworley.com Git - inverse-tax/blob - tax.js
3 function parse_table(as_text
) {
4 function parse_line(line
) {
5 return line
.trim().split(' ').filter(x
=> x
!== '').map(x
=> parseFloat(x
));
7 return as_text
.trim().split('\n').map(parse_line
);
10 function tax_table_from_table(table
) {
11 return table
.map(([start
, rate
], i
, table
) =>
12 [start
, i
< table
.length
- 1 ? table
[i
+1][0] : Infinity
, rate
/ 100.0]);
15 function parse_tax_table(as_text
) {
16 return tax_table_from_table(parse_table(as_text
));
20 return nums
.reduce((total
, num
) => total
+ num
, 0);
23 function tax(table
, income
) {
24 return sum(table
.map(([start
, end
, rate
]) =>
25 Math
.max(0, Math
.min(income
, end
) - start
) * rate
));
28 function apply_deductible(table
, deductible
) {
29 return table
.map(([start
, end
, rate
]) => [start
+ deductible
, end
+ deductible
, rate
]);
32 function merge_tax_tables(t1
, t2
) {
33 if (t1
.length
== 0) return t2
;
34 if (t2
.length
== 0) return t1
;
35 const [start1
, end1
, rate1
] = t1
[0];
36 const [start2
, end2
, rate2
] = t2
[0];
37 if (start1
== start2
) {
39 return [[start1
, end1
, rate1
+ rate2
]].concat(merge_tax_tables(t1
.slice(1), t2
.slice(1)));
42 return [[start1
, end1
, rate1
+ rate2
]].concat(merge_tax_tables(t1
.slice(1), [[end1
, end2
, rate2
]].concat(t2
.slice(1))));
44 return merge_tax_tables(t2
, t1
);
46 if (start1
< start2
) {
48 return [t1
[0]].concat(merge_tax_tables(t1
.slice(1), t2
));
50 return [[start1
, start2
, rate1
]].concat(merge_tax_tables([[start2
, end1
, rate1
]].concat(t1
.slice(1)), t2
));
52 return merge_tax_tables(t2
, t1
);
55 function invert(table
) {
57 // net = m * gross + b
59 // net - b = m * gross
60 // (net - b) / m = gross
61 // and the calculate the inverse's bounds
63 const ms
= table
.map(([start
, end
, rate
]) => 1 - rate
);
64 const full_brackets
= [0].concat(table
.map(([start
, end
, rate
]) => (end
- start
) * rate
)).slice(0, table
.length
);
65 function sum_lower_brackets(remaining_brackets
, acc
= 0) {
66 if (remaining_brackets
.length
== 0) return [];
67 return [acc
+ remaining_brackets
[0]].concat(sum_lower_brackets(remaining_brackets
.slice(1), acc
+ remaining_brackets
[0]));
69 const bs
= sum_lower_brackets(full_brackets
).map((lower_brackets
, i
) => {
70 const [start
, end
, rate
] = table
[i
];
72 // net = gross - lower_brackets - rate * (gross - start)
73 // net = gross - lower_brackets - rate * gross + rate * start
74 // net = gross - rate * gross - lower_brackets + rate * start
75 // net = (1 - rate) * gross - lower_brackets + rate * start
76 // net = m * gross - lower_brackets + rate * start
77 // \_____________________________/ - here is b
78 return rate
* start
- lower_brackets
;
80 const inverse_table
= table
.map(([start
, end
, rate
], i
) => {
83 return [m
* start
+ b
, m
* end
+ b
, m
, b
];
85 return function(net
) {
86 for (const [start
, end
, m
, b
] of inverse_table
) {
87 if (start
<= net
&& net
<= end
) {