The Bear's Den

Enter at your own risk

Tax Steps

Task 1: Increment Decrement

Submitted by: Mohammad Sajid Anwar


You are given a list of operations.

Write a script to return the final value after performing the given operations in order. The initial value is always 0.

Possible Operations:
++x or x++: increment by 1
--x or x--: decrement by 1

Example 1

Input: @operations = ("--x", "x++", "x++")
Output: 1

Operation "--x" =>  0 - 1 => -1
Operation "x++" => -1 + 1 =>  0
Operation "x++" =>  0 + 1 =>  1

Example 2

Input: @operations = ("x++", "++x", "x++")
Output: 3

Example 3

Input: @operations = ("x++", "++x", "--x", "x--")
Output: 0

Operation "x++" => 0 + 1 => 1
Operation "++x" => 1 + 1 => 2
Operation "--x" => 2 - 1 => 1
Operation "x--" => 1 - 1 => 0

Solution

Matching each operation against a regex that:

Prepending the extracted sign from the matching operation to a 1 to produce a valid number and take the sum over these gives the requested result.

Any operation not contained in the given set will be ignored as it gives a false regex matching result that has a numerical value of 0.

use strict;
use warnings;
use List::Util 'sum0';

sub inc_dec {
    sum0 map /^(?=.{3}$)x?([-+])\1x?$/ && "${1}1", @_
}

See the full solution to task 1.

Task 2: Tax Amount

Submitted by: Mohammad Sajid Anwar


You are given an income amount and tax brackets.

Write a script to calculate the total tax amount.

Example 1

Input: $income = 10, @tax = ([3, 50], [7, 10], [12,25])
Output: 1.65

1st tax bracket upto  3, tax is 50%.
2nd tax bracket upto  7, tax is 10%.
3rd tax bracket upto 12, tax is 25%.

Total Tax => (3 * 50/100) + (4 * 10/100) + (3 * 25/100)
          => 1.50 + 0.40 + 0.75
          => 2.65

Example 2

Input: $income = 2, @tax = ([1, 0], [4, 25], [5,50])
Output: 0.25

Total Tax => (1 * 0/100) + (1 * 25/100)
          => 0 + 0.25
          => 0.25

Example 3

Input: $income = 0, @tax = ([2, 50])
Output: 0

Solution

With a little pre-processing of the tax brackets, the final tax calculation can be simplified.

We are given \(n\) pairs \((u_i, t_i) \text{ for } 1 \le i \le n\) of upper bracket limits \(u_i\) and the corresponding tax rate \(t_i\). Presuming the the brackets to be sorted by ascending limits and converting percentages to floating point factors.

Let us consider \(n + 1\) triplets \((l_i, \hat{t}_i, c_i) \text{ for } 0 \le i \le n\) instead, where \(l_i\) are the lower bracket limits, \(\hat{t}_i\) are the tax rates and \(c_i\) are the cumulative sums over the maximum tax over all brackets. These values are defined as:

\[\begin{align*} l_i &= \begin{cases} 0& \text{if $i = 0$},\\ u_i& \text{if $i > 0$} \end{cases}\\ \hat{t}_i &= \begin{cases} t_{i+1}& \text{if $i < n$},\\ 0& \text{if $i = n$} \end{cases}\\ c_i &= \begin{cases} 0& \text{if $i = 0$},\\ c_{i-1} + (l_i - l_{i-1})t_i& \text{if $i >0$} \end{cases} \end{align*}\]

This new configuration has a final pseudo-bracket without upper limit and a tax rate of zero.

After identifying the bracket \(k\) a given income \(I\) belongs to as \(k = \max\,\{i | l_i \le I\}\), the total tax \(T\) can be calculated as

\[T = c_k + \hat{t}_k (I - l_k)\]

The index \(k\) can be found with a binary search using PDL::Primitive’s vsearch_bin_inclusive. Multiple calculations based on the same tax schema can be done using the same pre-processed data.

sub tax_pp pre-processes the given pairs returning the described triplets, which need to be given as the second argument to sub tax_amount.

use strict;
use warnings;
use PDL;
use PDL::NiceSlice;
use experimental 'signatures';

sub tax_pp {
    my $tax = pdl @_;
    $tax(1) /= 100;
    my $low = pdl(0)->append($tax((0)));

    cat $low,
        $tax((1))->append(pdl(0)),
        pdl(0)->append((($low(1:-1) - $low(0:-2)) * $tax((1)))->cumusumover);
}

sub tax_amount ($income, $tp) {
    my $tax = $tp(vsearch_bin_inclusive($income, $tp(,(0)));-);

    sclr $tax(2) + $tax(1) * ($income - $tax(0));
}

See the full solution to task 2.


If you have a question about this post or if you like to comment on it, feel free to open an issue in my github repository.