]>
git.scottworley.com Git - inverse-tax/blob - tax.js
d26db5fa15f0b8cf0cdd006fd4b19cc4f6e37076
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 parse_tax_table(as_text
) {
11 return parse_table(as_text
).map(([start
, rate
], i
, table
) =>
12 [start
, i
< table
.length
- 1 ? table
[i
+1][0] : Infinity
, rate
/ 100.0]);
16 return nums
.reduce((total
, num
) => total
+ num
, 0);
19 function tax(table
, income
) {
20 return sum(table
.map(([start
, end
, rate
]) =>
21 Math
.max(0, Math
.min(income
, end
) - start
) * rate
));
24 function apply_deductible(table
, deductible
) {
25 return table
.map(([start
, end
, rate
]) => [start
+ deductible
, end
+ deductible
, rate
]);
28 function merge_tax_tables(t1
, t2
) {
29 if (t1
.length
== 0) return t2
;
30 if (t2
.length
== 0) return t1
;
31 const [start1
, end1
, rate1
] = t1
[0];
32 const [start2
, end2
, rate2
] = t2
[0];
33 if (start1
== start2
) {
35 return [[start1
, end1
, rate1
+ rate2
]].concat(merge_tax_tables(t1
.slice(1), t2
.slice(1)));
38 return [[start1
, end1
, rate1
+ rate2
]].concat(merge_tax_tables(t1
.slice(1), [[end1
, end2
, rate2
]].concat(t2
.slice(1))));
40 return merge_tax_tables(t2
, t1
);
42 if (start1
< start2
) {
44 return [t1
[0]].concat(merge_tax_tables(t1
.slice(1), t2
));
46 return [[start1
, start2
, rate1
]].concat(merge_tax_tables([[start2
, end1
, rate1
]].concat(t1
.slice(1)), t2
));
48 return merge_tax_tables(t2
, t1
);
51 function invert(table
) {
52 if (table
.length
== 0) return x
=> x
;
55 // net = m * gross + b
57 // net - b = m * gross
58 // (net - b) / m = gross
59 // and the calculate the inverse's bounds
61 const ms
= table
.map(([start
, end
, rate
]) => 1 - rate
);
62 const full_brackets
= [[0]].concat(table
.map(([start
, end
, rate
]) => (end
- start
) * rate
)).slice(0, table
.length
);
63 function sum_lower_brackets(remaining_brackets
, acc
= 0) {
64 if (remaining_brackets
.length
== 0) return [];
65 return [acc
+ remaining_brackets
[0]].concat(sum_lower_brackets(remaining_brackets
.slice(1), acc
+ remaining_brackets
[0]));
67 const bs
= sum_lower_brackets(full_brackets
).map((lower_brackets
, i
) => {
68 const [start
, end
, rate
] = table
[i
];
70 // net = gross - lower_brackets - rate * (gross - start)
71 // net = gross - lower_brackets - rate * gross + rate * start
72 // net = gross - rate * gross - lower_brackets + rate * start
73 // net = (1 - rate) * gross - lower_brackets + rate * start
74 // net = m * gross - lower_brackets + rate * start
75 // \_____________________________/ - here is b
76 return rate
* start
- lower_brackets
;
78 const inverse_table
= table
.map(([start
, end
, rate
], i
) => {
81 return [(start
- b
) / m
, (end
- b
) / m
, m
, b
];
83 return function(net
) {
84 for (const [start
, end
, m
, b
] of inverse_table
) {
85 if (start
< net
&& net
< end
) {