Skip to content

4. Application Exercise – Tax Calculation

4.1. The Problem

We aim to write a program to calculate a taxpayer’s tax. We’ll consider the simplified case of a taxpayer who has only their salary to report:

  • The number of shares for the employee is calculated as nbParts = nbEnfants / 2 + 1 if they are unmarried, or nbEnfants / 2 + 2 if they are married, where nbEnfants is the number of children they have.
  • We calculate their taxable income R = 0.72 * S, where S is their annual salary
  • We calculate their family coefficient Q = R / N

We calculate their tax I based on the following data

12620.0
0
0
13,190
0.05
631
15,640
0.1
1,290.5
24,740
0.15
2,072.5
31,810
0.2
3,309.5
39,970
0.25
4900
48,360
0.3
6,898.5
55,790
0.35
9,316.5
92,970
0.4
12,106
127,860
0.45
16,754.5
151,250
0.50
23,147.5
172,040
0.55
30,710
195,000
0.60
39,312
0
0.65
49,062

Each row has 3 fields. To calculate tax I, we look for the first row where QF <= field1. For example, if QF = 30000, we will find the row

    24740        0.15        2072.5

Tax I is then equal to 0.15*R - 2072.5*nbParts. If QF is such that the condition QF<=field1 is never met, then the coefficients from the last row are used. Here:

    0                0.65        49062

which gives tax I = 0.65*R – 49062*nbParts.

4.2. Version with arrays (impots_01)

We present an initial program where:

  • the data needed to calculate the tax are in three arrays (limits, coeffR, coeffN)
  • the taxpayer data (married, children, salary) are in a first text file
  • the results of the tax calculation (married, children, salary, tax) are stored in a second text file

<?php

// definition of constants
$DATA = "data.txt";
$RESULTS = "results.txt";
$limits = array(12620, 13190, 15640, 24740, 31810, 39970, 48360, 55790, 92970, 127860, 151250, 172040, 195000);
$coeffR = array(0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65);
$coeffN = array(0, 631, 1290.5, 2072.5, 3309.5, 4900, 6898.5, 9316.5, 12106, 16754.5, 23147.5, 30710, 39312, 49062);

// Read data
$data = fopen($DATA, "r");
if (!$data) {
  print "Unable to open the data file [$DATA] for reading\n";
  exit;
}

// Open the results file
$results = fopen($RESULTS, "w");
if (!$results) {
  print "Unable to create the results file [$RESULTS]\n";
  exit;
}

// process the current line of the data file
while ($line = fgets($data, 100)) {
  // remove any end-of-line characters
  $line = cutNewLineChar($line);
  // retrieve the 3 fields married, children, salary that make up $line
  list($married, $children, $salary) = explode(",", $line);
  // calculate the tax
  $tax = calculateTaxes($married, $children, $salary, $limits, $coeffR, $coeffN);
  // write the result to the results file
  fputs($results, "$married:$children:$salary:$tax\n");
  // next taxpayer
}
// close the files
fclose($data);
fclose($results);

// end
exit;

// --------------------------------------------------------------------------
function cutNewLinechar($line) {
  // remove the end-of-line character from $line if it exists
  $L = strlen($line);  // line length
  while (substr($line, $L - 1, 1) == "\n" or substr($line, $L - 1, 1) == "\r") {
    $line = substr($line, 0, $L - 1);
    $L--;
  }
  // end
  return($line);
}

// --------------------------------------------------------------------------
function calculateTaxes($married, $children, $salary, $thresholds, $coeffR, $coeffN) {
  // $married: yes, no
  // $children: number of children
  // $salary: annual salary
  // $limits, $coeffR, $coeffN: data arrays used to calculate taxes
  
  // number of shares
  $married = strtolower($married);
  if ($married == "yes")
    $nbParts = $children / 2 + 2;
  else
    $nbParts = $children / 2 + 1;
  // add 1/2 share if there are at least 3 children
  if ($children >= 3)
    $nbParts+=0.5;
  // taxable income
  $taxableIncome = 0.72 * $salary;
  // family quotient
  $quotient = $taxableIncome / $numberOfChildren;
  // is added to the end of the limits array to stop the following loop
  array_push($limits, $quotient);
  // tax calculation
  $i = 0;
  while ($quotient > $limits[$i])
    $i++;
  // Since we placed $quotient at the end of the $limites array, the previous loop
  // cannot go beyond the bounds of the $limits array
  // now we can calculate the tax
  return floor($taxableIncome * $rate[$i] - $numberOfShares * $taxRate[$i]);
}
?>

The data file data.txt (married, children, salary):

yes,2,200000
no,2,200000
yes,3,200000
no,3,200000
yes,5,50000
no,0,3000000

The results.txt files (married, children, salary, tax) for the results obtained:

yes:2:200000:22504
no:2:200000:33388
yes:3:200000:16400
no:3:200000:22504
yes:5:50000:0
no:0:3000000:1354938

Comments

  • line 4: the name of the text file containing taxpayer data (married, children, salary)
  • line 5: the name of the text file containing the results (married, children, salary, tax) of the tax calculation
  • Lines 6–8: the three data tables used to calculate the tax
  • lines 11-15: open the taxpayer data file for reading
  • lines 18–22: open the results file for writing
  • line 25: loop to read the lines (married, children, salary) from the taxpayer file
  • line 27: the end-of-line character is removed
  • line 29: the components (married, children, salary) of the line are retrieved
  • line 31: tax is calculated
  • line 33: the tax is stored in the results file
  • lines 37-38: once the taxpayer file has been fully processed, the files are closed
  • line 44: the function that removes the end-of-line character from a line $line. The end-of-line character is the string "\r\n" on Windows systems, "\n" on Unix systems. The result is the input string without its end-of-line character.
  • lines 47-48: substr($string, $start, $size) returns the substring of $string starting at character $start and containing at most $size characters.
  • line 63: strtolower($string) converts $string to lowercase
  • line 76: array_push($array, $element) adds $element to the end of the $array. Note that the $limits array is passed by value to the calculateTax function (line 56). This addition of an element is therefore performed on a copy of the actual parameter, which remains unchanged.
  • line 84: the function floor($x) returns the integer value immediately less than $x.

4.3. Version with text files (impots_02)

This new version differs from the previous one only in that the data ($limites, $coeffR, $coeffN) needed to calculate the tax are now in a text file in the following format:

File impots.txt:

12620:13190:15640:24740:31810:39970:48360:55790:92970:127860:151250:172040:195000:0
0:0.05:0.1:0.15:0.2:0.25:0.3:0.35:0.4:0.45:0.5:0.55:0.6:0.65
0:631:1290.5:2072.5:3309.5:4900:6898.5:9316.5:12106:16754.5:23147.5:30710:39312:49062

The new version simply reads the data from the [impots.txt] file and places it into three arrays ($limites, $coeffR, $coeffN). This brings us back to the previous case. We present only the changes:


<?php

// definition of constants
$DATA = "data.txt";
$RESULTS = "results.txt";
$TAXES = "taxes.txt";

// The data needed to calculate the tax has been placed in the $IMPOTS file
// with one line per table in the form
// val1:val2:val3,...
list($error, $limits, $coeffR, $coeffN) = getTables($TAXES);

// Was there an error?
if ($error) {
  print "$error\n";
  exit;
}//if
// reading user data
...

// end
exit;

// --------------------------------------------------------------------------
function cutNewLinechar($line) {
  // remove the end-of-line character from $line if it exists
...
}

// --------------------------------------------------------------------------
function calculateTaxes($married, $children, $salary, $thresholds, $coeffR, $coeffN) {
  // $married: yes, no
  // $children: number of children
  // $salary: annual salary
  // $limits, $coeffR, $coeffN: data arrays used to calculate taxes
  ...
}

// --------------------------------------------------------------------------
function getTables($IMPOTS) {
  // $IMPOTS: the name of the file containing the data for the $limites, $coeffR, and $coeffN tables
  // Does the $IMPOTS file exist?
  if (!file_exists($IMPOTS))
    return array("The $IMPOTS file does not exist","","","");
  // read the file in blocks
  $tables = file($IMPOTS);
  if (!$tables)
    return array("Error while processing the $IMPOTS file","","","");
  // Create the 3 tables - assuming the lines are syntactically correct
  $limits = explode(":", cutNewLineChar($tables[0]));
  $coeffR = explode(":", cutNewLineChar($tables[1]));
  $coeffN = explode(":", cutNewLineChar($tables[2]));
  // end
  return array("", $limits, $coeffR, $coeffN);
}
?>

Comments

  • Line 11: The function getTables($IMPOTS) processes the text file $IMPOTS to extract the three tables ($limites, $coeffR, $coeffN). The result returned is ($error, $limites, $coeffR, $coeffN), where $error is an error message; it is empty if no error occurred.
  • Line 40: The getTables($IMPOTS) function.
  • line 43: the function files_exists(filename) returns the boolean true if the file filename exists, and false otherwise.
  • line 46: the file(filename) function reads the entire text file filename. It returns an array where each element is a line from the text file. Since the impots.txt file has three lines of text, the function will return an array with three elements.
  • Lines 50–52: Use the three retrieved lines to create the three arrays ($limits, $coeffR, $coeffN)

The results obtained are the same as those obtained in the previous version.