4. 应用练习 – 税费计算
4.1. 问题
我们的目标是编写一个程序来计算纳税人的税款。我们将考虑一个简化案例,即纳税人仅需申报工资收入:
- 员工的股份数量按以下公式计算:若未婚,则 nbParts = nbEnfants / 2 + 1;若已婚,则 nbParts = nbEnfants / 2 + 2,其中 nbEnfants 表示其子女数量。
- 我们计算他们的应税收入 R = 0.72 * S,其中 S 是他们的年薪
- 我们计算其家庭系数 Q = R / N
根据以下数据,我们计算其应纳税额 I
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 |
每行有 3 个字段。要计算税款 I,我们寻找第一个满足 QF <= 字段1 的行。例如,如果 QF = 30000,我们将找到该行
此时,Tax I 等于 0.15*R - 2072.5*nbParts。如果 QF 使得条件 QF<=field1 永远不成立,则使用最后一行中的系数。这里:
由此可得税额 I = 0.65*R – 49062*nbParts。
4.2. 使用数组的版本 (impots_01)
我们提供一个初始程序,其中:
- 用于计算税款的数据存储在三个数组中(limits、coeffR、coeffN)
- 纳税人数据(已婚、子女、工资)存储在第一个文本文件中
- 税款计算结果(已婚、子女、工资、税额)存储在第二个文本文件中
<?php
// definition of constants
$DATA = "data.txt";
$RESULTATS = "resultats.txt";
$limites = 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);
// reading data
$data = fopen($DATA, "r");
if (!$data) {
print "Impossible d'ouvrir en lecture le fichier des données [$DATA]\n";
exit;
}
// open results file
$résultats = fopen($RESULTATS, "w");
if (!$résultats) {
print "Impossible de créer le fichier des résultats [$RESULTATS]\n";
exit;
}
// use the current line of the data file
while ($ligne = fgets($data, 100)) {
// remove any end-of-line marker
$ligne = cutNewLineChar($ligne);
// we retrieve the 3 fields married,children,salary which form $ligne
list($marié, $enfants, $salaire) = explode(",", $ligne);
// tax calculation
$impôt = calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN);
// enter the result in the results file
fputs($résultats, "$marié:$enfants:$salaire:$impôt\n");
// next taxpayer
}
// close files
fclose($data);
fclose($résultats);
// end
exit;
// --------------------------------------------------------------------------
function cutNewLinechar($ligne) {
// delete the end-of-line mark from $ligne if it exists
$L = strlen($ligne); // // line length
while (substr($ligne, $L - 1, 1) == "\n" or substr($ligne, $L - 1, 1) == "\r") {
$ligne = substr($ligne, 0, $L - 1);
$L--;
}
// end
return($ligne);
}
// --------------------------------------------------------------------------
function calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN) {
// $marié : yes, no
// $enfants : number of children
// $salaire: annual salary
// $limites, $coeffR, $coeffN: tax calculation data tables
// number of shares
$marié = strtolower($marié);
if ($marié == "oui")
$nbParts = $enfants / 2 + 2;
else
$nbParts=$enfants / 2 + 1;
// an additional 1/2 share if at least 3 children
if ($enfants >= 3)
$nbParts+=0.5;
// taxable income
$revenuImposable = 0.72 * $salaire;
// family quotient
$quotient = $revenuImposable / $nbParts;
// is set at the end of the limit table to stop the following loop
array_push($limites, $quotient);
// tAX CALCULATION
$i = 0;
while ($quotient > $limites[$i])
$i++;
// because $quotient has been placed at the end of the $limites array, the previous loop
// cannot exceed the table $limites
// now we can calculate the tax
return floor($revenuImposable * $coeffR[$i] - $nbParts * $coeffN[$i]);
}
?>
数据文件 data.txt(已婚、子女、工资):
针对所得结果生成的 results.txt 文件(已婚、子女、薪资、税款):
oui:2:200000:22504
non:2:200000:33388
oui:3:200000:16400
non:3:200000:22504
oui:5:50000:0
non:0:3000000:1354938
注释
- 第4行:包含纳税人数据(已婚、子女、工资)的文本文件名称
- 第5行:包含税款计算结果(婚姻状况、子女、工资、税额)的文本文件名称
- 第6–8行:用于计算税款的三个数据表
- 第11–15行:打开纳税人数据文件进行读取
- 第18–22行:打开结果文件以进行写入
- 第25行:循环读取纳税人文件中的行(已婚、子女、工资)
- 第 27 行:移除换行符
- 第29行:提取该行的组成部分(婚姻状况、子女、工资)
- 第 31 行:计算税额
- 第 33 行:将税额存储到结果文件中
- 第 37-38 行:纳税人文件处理完毕后,关闭文件
- 第 44 行:该函数用于从字符串 $line 中移除换行符。在 Windows 系统中,换行符为字符串 "\r\n";在 Unix 系统中,换行符为 "\n"。处理结果是去除了换行符的原始输入字符串。
- 第 47-48 行:substr($string, $start, $size) 返回 $string 中从字符 $start 开始、长度不超过 $size 的子字符串。
- 第 63 行:strtolower($string) 将 $string 转换为小写
- 第 76 行:array_push($array, $element) 将 $element 添加到 $array 的末尾。请注意,$limits 数组是以值传递的方式传递给 calculateTax 函数的(第 56 行)。因此,此项元素的添加是在实际参数的副本上进行的,而实际参数本身保持不变。
- 第 84 行:floor($x) 函数返回小于 $x 的最小整数值。
4.3. 使用文本文件的版本 (impots_02)
此新版本与前一版本的唯一区别在于,计算税款所需的数据($limites、$coeffR、$coeffN)现在存储在一个文本文件中,格式如下:
文件 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
新版本仅需从 [impots.txt] 文件中读取数据,并将其放入三个数组($limites、$coeffR、$coeffN)中。这使我们回到了之前的案例。我们仅展示更改部分:
<?php
// definition of constants
$DATA = "data.txt";
$RESULTATS = "resultats.txt";
$IMPOTS = "impots.txt";
// the data required to calculate the tax has been placed in the $IMPOTS file
// one line per table in the form
// val1:val2:val3,...
list($erreur, $limites, $coeffR, $coeffN) = getTables($IMPOTS);
// was there a mistake?
if ($erreur) {
print "$erreur\n";
exit;
}//if
// reading user data
...
// end
exit;
// --------------------------------------------------------------------------
function cutNewLinechar($ligne) {
// delete the end-of-line mark from $ligne if it exists
...
}
// --------------------------------------------------------------------------
function calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN) {
// $marié : yes, no
// $enfants : number of children
// $salaire: annual salary
// $limites, $coeffR, $coeffN: tax calculation data tables
...
}
// --------------------------------------------------------------------------
function getTables($IMPOTS) {
// $IMPOTS: name of the file containing data from tables $limites, $coeffR, $coeffN
// does the $IMPOTS file exist?
if (!file_exists($IMPOTS))
return array("Le fichier $IMPOTS n'existe pas","","","");
// file block playback
$tables = file($IMPOTS);
if (!$tables)
return array("Erreur lors de l'exploitation du fichier $IMPOTS","","","");
// create the 3 tables - assume the rows are syntactically correct
$limites = explode(":", cutNewLineChar($tables[0]));
$coeffR = explode(":", cutNewLineChar($tables[1]));
$coeffN = explode(":", cutNewLineChar($tables[2]));
// end
return array("", $limites, $coeffR, $coeffN);
}
?>
注释
- 第 11 行:函数 getTables($IMPOTS) 处理文本文件 $IMPOTS 以提取三个表格 ($limites, $coeffR, $coeffN)。返回的结果为 ($error, $limites, $coeffR, $coeffN),其中 $error 是一个错误消息;若未发生错误,则其值为空。
- 第 40 行:getTables($IMPOTS) 函数。
- 第 43 行:函数 files_exists(filename) 若文件 filename 存在则返回布尔值 true,否则返回 false。
- 第 46 行:file(filename) 函数读取文本文件 filename 的全部内容。它返回一个数组,其中每个元素代表文本文件中的一行。由于 impots.txt 文件包含三行文本,该函数将返回一个包含三个元素的数组。
- 第 50–52 行:使用读取到的三行文本创建三个数组($limits、$coeffR、$coeffN)
所得结果与上一版本的结果相同。