Camel
Peter
Peter Campbell Smith

Up, down, and pay your tax

Weekly challenge 323 — 26 May 2025

Week 323: 26 May 2025

Task 2

Task — Tax amount

You are given an income amount and tax brackets. Write a script to calculate the total tax amount.

Examples


Example 1
Input: $income = 10, @tax = ([3, 50], [7, 10], [12,25])
Output: 2.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

Analysis

Sadly, this is a calculation I have done every year since I started working about 55 years ago.

It's just a case of working out how much income falls in each bracket. For each bracket where your income is less than equal to the top you pay the width of the bracket times its rate.

Then for the bracket that follows those you pay its rate times whatever income (maybe zero) that has not been taxed yet.

This is the way income tax is calculated in the UK and I have included a couple of examples using this year's UK tax brackets*. Other countries do it differently, with a more continuously varying percentage as income increases.

* I accept no responsibility if you use my algorithm to do your tax return!

Try it 

Try running the script with any input:



example: 50000



example: [5000, 0], [30000, 20], [1000000, 40]

Script


#!/usr/bin/perl

# Blog: http://ccgi.campbellsmiths.force9.co.uk/challenge

use v5.26;    # The Weekly Challenge - 2025-05-26
use utf8;     # Week 323 - task 2 - Tax amount
use warnings; # Peter Campbell Smith
binmode STDOUT, ':utf8';
use Encode;

tax_amount(10, [[3, 50], [7, 10], [12, 25]]);
tax_amount(2, [[1, 0], [4, 25], [5,50]]);
tax_amount(0, [[2, 50]]);

# UK 2025/6 tax rates
tax_amount(80000, [[12570, 0], [50270, 20], [125140, 40], [1e10, 45]]);
tax_amount(150000, [[12570, 0], [50270, 20], [125140, 40], [1e10, 45]]);

sub tax_amount {
    
    my ($income, $tax_rates, $tax, $band_start, $band_end, $band, $rate, $rates, $taxable, $explain);
    
    # initialise
    ($income, $tax_rates) = @_;
    $tax = 0;
    $explain = '';
    
    # loop over tax bands
    $band_start = 0;
    for $band (@$tax_rates) {
        ($band_end, $rate) = @$band;
        $rates .= qq[up to $band_end at $rate%, ];
        next if $income <= $band_start;
        
        # tax payable in this band
        $taxable = $income > $band_end ? ($band_end - $band_start) : ($income - $band_start);
        $tax += $taxable * $rate / 100;
        $explain .= qq[$taxable at $rate%, ];
        $band_start = $band_end;
    }
        
    say qq[\nInput:  \$income = $income, \@tax = (] . substr($rates, 0, -2) . q[)];
    say qq[Output: \$tax = ] . sprintf('%.2f', $tax) . 
        ($tax ? ' being '. substr($explain, 0, -2) : '');
}

Output


Input:  $income = 10, @tax = (up to 3 at 50%,
   up to 7 at 10%, up to 12 at 25%)
Output: $tax = 2.65 being 3 at 50%, 4 at 10%, 3 at 25%

Input:  $income = 2, @tax = (up to 1 at 0%,
   up to 4 at 25%, up to 5 at 50%)
Output: $tax = 0.25 being 1 at 0%, 1 at 25%

Input:  $income = 0, @tax = (up to 2 at 50%)
Output: $tax = 0.00

Input:  $income = 80000, @tax = (up to 12570 at 0%,
   up to 50270 at 20%, up to 125140 at 40%,
   up to 10000000000 at 45%)
Output: $tax = 19432.00 being 12570 at 0%, 37700 at 20%,
   29730 at 40%

Input:  $income = 150000, @tax = (up to 12570 at 0%,
   up to 50270 at 20%, up to 125140 at 40%,
   up to 10000000000 at 45%)
Output: $tax = 48675.00 being 12570 at 0%, 37700 at 20%,
   74870 at 40%, 24860 at 45%

 

Any content of this website which has been created by Peter Campbell Smith is in the public domain