Skip to content

4. Exercice d'application - IMPOTS

4.1. Le problème

On se propose d'écrire un programme permettant de calculer l'impôt d'un contribuable. On se place dans le cas simplifié d'un contribuable n'ayant que son seul salaire à déclarer :

  • on calcule le nombre de parts du salarié nbParts=nbEnfants/2 +1 s'il n'est pas marié, nbEnfants/2+2 s'il est marié, où nbEnfants est son nombre d'enfants.
  • on calcule son revenu imposable R=0.72*S où S est son salaire annuel
  • on calcule son coefficient familial Q=R/N

on calcule son impôt I d'après les données suivantes

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

Chaque ligne a 3 champs. Pour calculer l'impôt I, on recherche la première ligne où QF<=champ1. Par exemple, si QF=30000 on trouvera la ligne

    24740        0.15        2072.5

L'impôt I est alors égal à 0.15*R - 2072.5*nbParts. Si QF est tel que la relation QF<=champ1 n'est jamais vérifiée, alors ce sont les coefficients de la dernière ligne qui sont utilisés. Ici :

    0                0.65        49062

ce qui donne l'impôt I=0.65*R – 49062*nbParts.

4.2. Version avec tableaux (impots_01)

Nous présentons un premier programme où :

  • les données nécessaires au calcul de l'impôt sont dans trois tableaux (limites, coeffR, coeffN)
  • les données des contribuables (marié, enfants, salaire) sont dans un premier fichier texte
  • les résultats du calcul de l'impôt (marié, enfants, salaire, impôt) sont mémorisés dans un second fichier texte

<?php

// définition des constantes
$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);

// lecture des données
$data = fopen($DATA, "r");
if (!$data) {
  print "Impossible d'ouvrir en lecture le fichier des données [$DATA]\n";
  exit;
}

// ouverture fichier des résultats
$résultats = fopen($RESULTATS, "w");
if (!$résultats) {
  print "Impossible de créer le fichier des résultats [$RESULTATS]\n";
  exit;
}

// on exploite la ligne courante du fichier des données
while ($ligne = fgets($data, 100)) {
  // on enlève l'éventuelle marque de fin de ligne
  $ligne = cutNewLineChar($ligne);
  // on récupère les 3 champs marié,enfants,salaire qui forment $ligne
  list($marié, $enfants, $salaire) = explode(",", $ligne);
  // on calcule l'impôt
  $impôt = calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN);
  // on inscrit le résultat dans le fichier des résultats
  fputs($résultats, "$marié:$enfants:$salaire:$impôt\n");
  // contribuable suivant
}
// on ferme les fichiers
fclose($data);
fclose($résultats);

// fin
exit;

// --------------------------------------------------------------------------
function cutNewLinechar($ligne) {
  // on supprime la marque de fin de ligne de $ligne si elle existe
  $L = strlen($ligne);  // longueur ligne
  while (substr($ligne, $L - 1, 1) == "\n" or substr($ligne, $L - 1, 1) == "\r") {
    $ligne = substr($ligne, 0, $L - 1);
    $L--;
  }
  // fin
  return($ligne);
}

// --------------------------------------------------------------------------
function calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN) {
  // $marié : oui, non
  // $enfants : nombre d'enfants
  // $salaire : salaire annuel
  // $limites, $coeffR, $coeffN : les tableaux des données permettant le calcul de l'impôt
  
  // nombre de parts
  $marié = strtolower($marié);
  if ($marié == "oui")
    $nbParts = $enfants / 2 + 2;
  else
    $nbParts=$enfants / 2 + 1;
  // une 1/2 part de plus si au moins 3 enfants
  if ($enfants >= 3)
    $nbParts+=0.5;
  // revenu imposable
  $revenuImposable = 0.72 * $salaire;
  // quotient familial
  $quotient = $revenuImposable / $nbParts;
  // est mis à la fin du tableau limites pour arrêter la boucle qui suit
  array_push($limites, $quotient);
  // calcul de l'impôt
  $i = 0;
  while ($quotient > $limites[$i])
    $i++;
  // du fait qu'on a placé $quotient à la fin du tableau $limites, la boucle précédente
  // ne peut déborder du tableau $limites
  // maintenant on peut calculer l'impôt
  return floor($revenuImposable * $coeffR[$i] - $nbParts * $coeffN[$i]);
}
?>

Le fichier des données data.txt (marié, enfants, salaire) :

oui,2,200000
non,2,200000
oui,3,200000
non,3,200000
oui,5,50000
non,0,3000000

Les fichier résultats.txt (marié, enfants, salaire, impôt) des résultats obtenus :

oui:2:200000:22504
non:2:200000:33388
oui:3:200000:16400
non:3:200000:22504
oui:5:50000:0
non:0:3000000:1354938

Commentaires

  • ligne 4 : le nom du fichier texte contenant les données des contribuables (marié, enfants, salaire)
  • ligne 5 : le nom du fichier texte contenant les résultats (marié, enfants, salaire, impôt) du calcul de l'impôt
  • lignes 6-8 : les trois tableaux des données permettant le calcul de l'impôt
  • lignes 11-15 : ouverture en lecture du fichier des données contribuables
  • lignes 18-22 : ouverture en écriture du fichier des résultats
  • ligne 25 : boucle de lecture des lignes (marié, enfants, salaire) du fichier des contribuables
  • ligne 27 : la marque de fin de ligne est enlevée
  • ligne 29 : les composantes (marié, enfants, salaire) de la ligne sont récupérées
  • ligne 31 : l'impôt est calculé
  • ligne 33 : l'impôt est mémorisé dans le fichier des résultats
  • lignes 37-38 : une fois le fichier des contribuables exploité totalement, les fichiers sont fermés
  • ligne 44 : la fonction qui supprime la marque de fin de ligne d'une ligne $ligne. La marque de fin de ligne est la chaîne "\r\n" sur les systèmes windows, "\n" sur les systèmes Unix. Le résultat est la chaîne d'entrée sans sa marque de fin de ligne.
  • lignes 47-48 : substr($chaîne,$début,$taille) est la sous-chaîne de $chaîne commençant au caractère $début et ayant au plus $taille caractères.
  • ligne 63 : strtolower($chaîne) rend $chaîne en minuscules
  • ligne 76 : array_push($tableau,$élément) ajoute $élément à la fin du tableau $tableau. On notera que le tableau $limites est passé par valeur à la fonction calculerImpot (ligne 56). Cet ajout d'élément se fait donc sur la copie du paramètre effectif, celui-ci restant inchangé.
  • ligne 84 : la fonction floor($x) rend la valeur entière immédiatement inférieure à $x.

4.3. Version avec fichiers texte (impots_02)

Cette nouvelle version ne diffère de la précédente que par le fait que les données ($limites, $coeffR, $coeffN) nécessaires au calcul de l'impôt sont maintenant dans un fichier texte sous la forme suivante :

Fichier 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

La nouvelle version se contente de lire les données du fichier [impots.txt] afin de les mettre dans trois tableaux ($limites, $coeffR, $coeffN). On est alors ramené au cas précédent. Nous ne présentons que les changements :


<?php

// définition des constantes
$DATA = "data.txt";
$RESULTATS = "resultats.txt";
$IMPOTS = "impots.txt";

// les données nécessaires au calcul de l'impôt ont été placées dans le fichier $IMPOTS
// à raison d'une ligne par tableau sous la forme
// val1:val2:val3,...
list($erreur, $limites, $coeffR, $coeffN) = getTables($IMPOTS);

// y-a-t-il eu une erreur ?
if ($erreur) {
  print "$erreur\n";
  exit;
}//if
// lecture des données utilisateur
...

// fin
exit;

// --------------------------------------------------------------------------
function cutNewLinechar($ligne) {
  // on supprime la marque de fin de ligne de $ligne si elle existe
...
}

// --------------------------------------------------------------------------
function calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN) {
  // $marié : oui, non
  // $enfants : nombre d'enfants
  // $salaire : salaire annuel
  // $limites, $coeffR, $coeffN : les tableaux des données permettant le calcul de l'impôt
  ...
}

// --------------------------------------------------------------------------
function getTables($IMPOTS) {
  // $IMPOTS : le nom du fichier contenant les données des tables $limites, $coeffR, $coeffN
  // le fichier $IMPOTS existe-t-il ?
  if (!file_exists($IMPOTS))
    return array("Le fichier $IMPOTS n'existe pas","","","");
  // lecture en bloc du fichier
  $tables = file($IMPOTS);
  if (!$tables)
    return array("Erreur lors de l'exploitation du fichier $IMPOTS","","","");
  // création des 3 tables - on suppose que les lignes sont syntaxiquement correctes
  $limites = explode(":", cutNewLineChar($tables[0]));
  $coeffR = explode(":", cutNewLineChar($tables[1]));
  $coeffN = explode(":", cutNewLineChar($tables[2]));
  // fin
  return array("", $limites, $coeffR, $coeffN);
}
?>

Commentaires

  • ligne 11 : la fonction getTables($IMPOTS) exploite le fichier texte $IMPOTS pour en extraire les trois tableaux ($limites, $coeffR, $coeffN). Le résultat rendu est ($erreur, $limites, $coeffR, $coeffN) où $erreur est un message d'erreur, vide s'il n'y a pas eu d'erreur.
  • ligne 40 : la fonction getTables($IMPOTS).
  • ligne 43 : la fonction files_exists(nom_fichier) rend le booléen true si le fichier nom_fichier existe, le booléen false sinon.
  • ligne 46 : la fonction file(nom_fichier) lit tout le fichier texte nom_fichier. Elle rend un tableau où chaque élément est une ligne du fichier texte. Comme ici, le fichier impots.txt a trois lignes de texte, la fonction va rendre un tableau à trois éléments.
  • lignes 50-52 : exploitation des trois lignes récupérées pour créer les trois tableaux ($limites, $coeffR, $coeffN)

Les résultats obtenus sont les mêmes qu'obtenus dans la version précédente.