4. Esercizio pratico - IMPOTS
4.1. Il problema
Si propone di scrivere un programma che consenta di calcolare l'imposta di un contribuente. Si considera il caso semplificato di un contribuente che abbia da dichiarare solo il proprio stipendio:
- si calcola il numero di quote del dipendente nbParts = nbEnfants/2 + 1 se non è sposato, nbEnfants/2+2 se è sposato, dove nbEnfants è il numero dei suoi figli.
- si calcola il suo reddito imponibile R=0,72*S, dove S è il suo stipendio annuale
- si calcola il suo coefficiente familiare Q = R/N
si calcola la sua imposta I in base ai seguenti dati
12620,0 | 0 | 0 |
13.190 | 0,05 | 631 |
15640 | 0,1 | 1290,5 |
24.740 | 0,15 | 2072,5 |
31810 | 0,2 | 3309,5 |
39.970 | 0,25 | 4900 |
48360 | 0,3 | 6898,5 |
55790 | 0,35 | 9316,5 |
92970 | 0,4 | 12106 |
127.860 | 0,45 | 16754,5 |
151250 | 0,50 | 23147,5 |
172.040 | 0,55 | 30710 |
195.000 | 0,60 | 39312 |
0 | 0,65 | 49062 |
Ogni riga ha 3 campi. Per calcolare l'imposta I, si cerca la prima riga in cui QF<=campo1. Ad esempio, se QF=30000, si troverà la riga
L'imposta I è quindi pari a 0,15*R - 2072,5*nbParts. Se QF è tale che la relazione QF<=campo1 non è mai soddisfatta, allora vengono utilizzati i coefficienti dell’ultima riga. In questo caso:
il che dà l’imposta I=0,65*R – 49062*nbParts.
4.2. Versione con tabelle (impots_01)
Presentiamo un primo programma in cui:
- i dati necessari per il calcolo dell’imposta si trovano in tre tabelle (limiti, coeffR, coeffN)
- i dati dei contribuenti (stato civile, figli, stipendio) si trovano in un primo file di testo
- i risultati del calcolo dell’imposta (stato civile, figli, stipendio, imposta) sono memorizzati in un secondo file di testo
<?php
// definizione delle costanti
$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);
// lettura dei dati
$data = fopen($DATA, "r");
if (!$data) {
print "Impossible d'ouvrir en lecture le fichier des données [$DATA]\n";
exit;
}
// apertura del file dei risultati
$résultats = fopen($RESULTATS, "w");
if (!$résultats) {
print "Impossible de créer le fichier des résultats [$RESULTATS]\n";
exit;
}
// si elabora la riga corrente del file dei dati
while ($ligne = fgets($data, 100)) {
// si rimuove l'eventuale carattere di fine riga
$ligne = cutNewLineChar($ligne);
// si recuperano i 3 campi «coniuge», «figli» e «stipendio» che formano $ligne
list($marié, $enfants, $salaire) = explode(",", $ligne);
// si calcola l’imposta
$impôt = calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN);
// si inserisce il risultato nel file dei risultati
fputs($résultats, "$marié:$enfants:$salaire:$impôt\n");
// contribuente successivo
}
// si chiudono i file
fclose($data);
fclose($résultats);
// fine
exit;
// --------------------------------------------------------------------------
function cutNewLinechar($ligne) {
// si elimina il carattere di fine riga da $ligne, se presente
$L = strlen($ligne); // lunghezza riga
while (substr($ligne, $L - 1, 1) == "\n" or substr($ligne, $L - 1, 1) == "\r") {
$ligne = substr($ligne, 0, $L - 1);
$L--;
}
// fine
return($ligne);
}
// --------------------------------------------------------------------------
function calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN) {
// $marié: sì, no
// $enfants: numero di figli
// $salaire: stipendio annuo
// $limites, $coeffR, $coeffN: tabelle dei dati che consentono il calcolo dell'imposta
// numero di quote
$marié = strtolower($marié);
if ($marié == "oui")
$nbParts = $enfants / 2 + 2;
else
$nbParts=$enfants / 2 + 1;
// una quota aggiuntiva di 1/2 se ci sono almeno 3 figli
if ($enfants >= 3)
$nbParts+=0.5;
// reddito imponibile
$revenuImposable = 0.72 * $salaire;
// quoziente familiare
$quotient = $revenuImposable / $nbParts;
// viene inserito alla fine della tabella dei limiti per interrompere il ciclo successivo
array_push($limites, $quotient);
// calcolo dell’imposta
$i = 0;
while ($quotient > $limites[$i])
$i++;
// poiché $quotient è stato inserito alla fine della tabella $limites, il ciclo precedente
// non può andare oltre i limiti della tabella $limites
// ora è possibile calcolare l’imposta
return floor($revenuImposable * $coeffR[$i] - $nbParts * $coeffN[$i]);
}
?>
Il file dei dati data.txt (stato civile, figli, stipendio):
I file résultats.txt (stato civile, figli, stipendio, imposte) dei risultati ottenuti:
oui:2:200000:22504
non:2:200000:33388
oui:3:200000:16400
non:3:200000:22504
oui:5:50000:0
non:0:3000000:1354938
Commenti
- riga 4: il nome del file di testo contenente i dati dei contribuenti (stato civile, figli, stipendio)
- riga 5: il nome del file di testo contenente i risultati (stato civile, figli, stipendio, imposta) del calcolo dell'imposta
- righe 6-8: le tre tabelle di dati che consentono il calcolo dell’imposta
- righe 11-15: apertura in lettura del file dei dati dei contribuenti
- righe 18-22: apertura in scrittura del file dei risultati
- riga 25: ciclo di lettura delle righe (stato civile, figli, stipendio) del file dei contribuenti
- riga 27: il carattere di fine riga viene rimosso
- riga 29: vengono recuperate le componenti (coniuge, figli, stipendio) della riga
- riga 31: viene calcolata l'imposta
- riga 33: l'imposta viene memorizzata nel file dei risultati
- righe 37-38: una volta elaborato completamente il file dei contribuenti, i file vengono chiusi
- riga 44: la funzione che rimuove il carattere di fine riga da una riga $ligne. Il carattere di fine riga è la stringa "\r\n" sui sistemi Windows, "\n" sui sistemi Unix. Il risultato è la stringa di input senza il carattere di fine riga.
- righe 47-48: substr($chaîne,$début,$taille) è la sottostringa di $chaîne che inizia dal carattere $début e contiene al massimo $taille caratteri.
- riga 63: strtolower($chaîne) restituisce $chaîne in minuscolo
- riga 76: array_push($tableau,$élément) aggiunge $élément alla fine dell'array $tableau. Si noti che la tabella $limites è stata passata per valore alla funzione calculerImpot (riga 56: )). L’aggiunta di questo elemento avviene quindi sulla copia del parametro effettivo, che rimane inalterato.
- riga 84: la funzione floor($x) restituisce il valore intero immediatamente inferiore a $x.
4.3. Versione con file di testo (impots_02)
Questa nuova versione differisce dalla precedente solo per il fatto che i dati ($limites, $coeffR, $coeffN) necessari per il calcolo dell’imposta si trovano ora in un file di testo nella forma seguente:
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
La nuova versione si limita a leggere i dati dal file [impots.txt] per inserirli in tre tabelle ($limites, $coeffR, $coeffN). Ci si ritrova quindi nella situazione precedente. Riportiamo solo le modifiche:
<?php
// definizione delle costanti
$DATA = "data.txt";
$RESULTATS = "resultats.txt";
$IMPOTS = "impots.txt";
// i dati necessari per il calcolo dell'imposta sono stati inseriti nel file $IMPOTS
// con una riga per ogni tabella nella forma
// val1:val2:val3,...
list($erreur, $limites, $coeffR, $coeffN) = getTables($IMPOTS);
// Si è verificato un errore?
if ($erreur) {
print "$erreur\n";
exit;
}//if
// lettura dei dati utente
...
// fine
exit;
// --------------------------------------------------------------------------
function cutNewLinechar($ligne) {
// si rimuove il carattere di fine riga da $ligne se presente
...
}
// --------------------------------------------------------------------------
function calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN) {
// $marié: sì, no
// $enfants: numero di figli
// $salaire: stipendio annuo
// $limites, $coeffR, $coeffN: tabelle dei dati che consentono il calcolo dell'imposta
...
}
// --------------------------------------------------------------------------
function getTables($IMPOTS) {
// $IMPOTS: il nome del file contenente i dati delle tabelle $limites, $coeffR, $coeffN
// Il file $IMPOTS esiste?
if (!file_exists($IMPOTS))
return array("Le fichier $IMPOTS n'existe pas","","","");
// lettura in blocco del file
$tables = file($IMPOTS);
if (!$tables)
return array("Erreur lors de l'exploitation du fichier $IMPOTS","","","");
// creazione delle 3 tabelle - si presume che le righe siano sintatticamente corrette
$limites = explode(":", cutNewLineChar($tables[0]));
$coeffR = explode(":", cutNewLineChar($tables[1]));
$coeffN = explode(":", cutNewLineChar($tables[2]));
// fine
return array("", $limites, $coeffR, $coeffN);
}
?>
Commenti
- riga 11: la funzione getTables($IMPOTS) utilizza il file di testo $IMPOTS per estrarne le tre tabelle ($limites, $coeffR, $coeffN). Il risultato restituito è ($erreur, $limites, $coeffR, $coeffN), dove $erreur è un messaggio di errore, vuoto se non si è verificato alcun errore.
- riga 40: la funzione getTables($IMPOTS).
- riga 43: la funzione files_exists(nom_fichier) restituisce il valore booleano true se il file nom_fichier esiste, altrimenti il valore booleano false.
- riga 46: la funzione file(nom_fichier) legge l'intero file di testo nom_fichier. Restituisce un array in cui ogni elemento corrisponde a una riga del file di testo. Poiché in questo caso il file impots.txt contiene tre righe di testo, la funzione restituirà un array composto da tre elementi.
- righe 50-52: utilizzo delle tre righe recuperate per creare i tre array ($limites, $coeffR, $coeffN)
I risultati ottenuti sono gli stessi di quelli della versione precedente.