#! /usr/bin/perl use POSIX qw/mktime/; use strict; use warnings; use Getopt::Long; my @tax_brackets = ( 6000, 0.17, 25000, 0.30, 75000, 0.42, 150000, 0.47 ); my @medicare_levy = ( 0, 0.015, 50000, 0.025 ); sub calc_from_brackets { my ($amount,@brackets) = @_; my $value = 0; my $last_ratio = 0; while(@brackets) { my $threshold = shift @brackets; my $ratio = shift @brackets; my $delta_ratio = $ratio - $last_ratio; my $t = $amount-$threshold; return $value if $t<=0; $value += ($delta_ratio*$t); $last_ratio = $ratio; } $value; }; sub calc_from_intervals { my ($amount,@intervals) = @_; my $final_ratio = 0; while(@intervals) { my $threshold = shift @intervals; my $ratio = shift @intervals; if($amount>=$threshold) { $final_ratio = $ratio; } } return $amount*$final_ratio; } sub incometax { return calc_from_brackets($_[0],@tax_brackets); } sub medicare { return calc_from_intervals($_[0],@medicare_levy); } sub taxedincome { my ($income) = @_; return $income-incometax($income)-medicare($income); } sub min { my ($a,$b) = @_; return ($a<$b)?$a:$b; } # Given a taxed income amount, determine the taxable income. # This is possible except for the "double-up" interval where the # medicare levy jumps up. We take the lowest taxable income in that case. # For this function the taxable income function is treated as a series # of straight lines on an x-y graph. We determine the line which the # taxed income (horizontal) line intercepts, and determine the taxed income # (x value) at that point. sub untaxed { my ($taxed) = @_; my @brackets = @tax_brackets; my @intervals = @medicare_levy; my ($x,$y) = (0,0,0,0); my ($tax,$medicare) = (0,0); while(1) { # determine if we are on the right line my $max = undef; @brackets and $max = $brackets[0]; if(@intervals) { if(defined $max) { $max = min($max,$intervals[0]); } else { $max = $intervals[0]; } } my $taxable = ($taxed-$y)/(1-$tax-$medicare)+$x; if(!defined $max || $taxable <= $max) { return $taxable; } # we aren't, so figure out the next line along if(@intervals && (!@brackets || $intervals[0] < $brackets[0])) { my $x2 = shift @intervals; my $new_tax = shift @intervals; $y += ($x2-$x) * (1-$tax-$medicare) - ($new_tax-$medicare)*$x2; $x = $x2; $medicare = $new_tax; } else { my $x2 = shift @brackets; my $new_tax = shift @brackets; $y += ($x2-$x) * (1-$tax-$medicare); $x = $x2; $tax = $new_tax; } } } for (my $income = 0; $income < 200000; $income += 2000) { my $taxed = taxedincome($income); my $income2 = untaxed($taxed); printf("%6d %6d %6d %s\n", $income,$taxed,$income2,($income2==$income)?".":"X" ); }