4. Ćwiczenie praktyczne – IMPOTS
4.1. Zadanie
Zadaniem jest napisanie programu umożliwiającego obliczenie podatku podatnika. Rozważamy uproszczony przypadek podatnika, który ma do zadeklarowania wyłącznie swoje wynagrodzenie:
- liczy się liczbę udziałów pracownika według wzoru nbParts = nbEnfants/2 + 1, jeśli nie jest żonaty, nbEnfants/2+2, jeśli jest żonaty, gdzie nbEnfants to liczba jego dzieci.
- Następnie oblicza się jego dochód podlegający opodatkowaniu R = 0,72 * S, gdzie S to jego roczne wynagrodzenie
- oblicza się jego współczynnik rodzinny Q = R/N
oblicza się jego podatek I na podstawie następujących danych
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 |
127860 | 0,45 | 16754,5 |
151250 | 0,50 | 23147,5 |
172 040 | 0,55 | 30710 |
195 000 | 0,60 | 39312 |
0 | 0,65 | 49062 |
Każdy wiersz zawiera 3 pola. Aby obliczyć podatek I, należy znaleźć pierwszy wiersz, w którym QF <= pole1. Na przykład, jeśli QF = 30000, znajdziemy wiersz
Podatek I wynosi wówczas 0,15*R – 2072,5*nbParts. Jeśli QF jest takie, że relacja QF <= pole1 nigdy nie jest spełniona, wówczas stosuje się współczynniki z ostatniego wiersza. W tym przypadku:
co daje podatek I = 0,65*R – 49062*nbParts.
4.2. Wersja z tabelami (impots_01)
Przedstawiamy pierwszy program, w którym:
- dane niezbędne do obliczenia podatku znajdują się w trzech tabelach (limity, coeffR, coeffN)
- dane podatników (stan cywilny, dzieci, wynagrodzenie) znajdują się w pierwszym pliku tekstowym
- wyniki obliczeń podatku (stan cywilny, dzieci, wynagrodzenie, podatek) są zapisane w drugim pliku tekstowym
<?php
// definicja stałych
$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);
// odczyt danych
$data = fopen($DATA, "r");
if (!$data) {
print "Impossible d'ouvrir en lecture le fichier des données [$DATA]\n";
exit;
}
// otwarcie pliku wyników
$résultats = fopen($RESULTATS, "w");
if (!$résultats) {
print "Impossible de créer le fichier des résultats [$RESULTATS]\n";
exit;
}
// przetwarzanie bieżącego wiersza pliku danych
while ($ligne = fgets($data, 100)) {
// usuwanie ewentualnego znaku końca linii
$ligne = cutNewLineChar($ligne);
// pobierane są 3 pola: „marié”, „enfants” i „salaire”, które tworzą $ligne
list($marié, $enfants, $salaire) = explode(",", $ligne);
// oblicza się podatek
$impôt = calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN);
// wynik zapisuje się w pliku wyników
fputs($résultats, "$marié:$enfants:$salaire:$impôt\n");
// kolejny podatnik
}
// zamykamy pliki
fclose($data);
fclose($résultats);
// koniec
exit;
// --------------------------------------------------------------------------
function cutNewLinechar($ligne) {
// usuwa się znak końca linii z $ligne, jeśli istnieje
$L = strlen($ligne); // długość wiersza
while (substr($ligne, $L - 1, 1) == "\n" or substr($ligne, $L - 1, 1) == "\r") {
$ligne = substr($ligne, 0, $L - 1);
$L--;
}
// koniec
return($ligne);
}
// --------------------------------------------------------------------------
function calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN) {
// $marié: tak, nie
// $enfants: liczba dzieci
// $salaire: roczne wynagrodzenie
// $limites, $coeffR, $coeffN: tabele danych umożliwiające obliczenie podatku
// liczba udziałów
$marié = strtolower($marié);
if ($marié == "oui")
$nbParts = $enfants / 2 + 2;
else
$nbParts=$enfants / 2 + 1;
// dodatkowa połowa udziału, jeśli jest co najmniej troje dzieci
if ($enfants >= 3)
$nbParts+=0.5;
// dochód podlegający opodatkowaniu
$revenuImposable = 0.72 * $salaire;
// współczynnik rodzinny
$quotient = $revenuImposable / $nbParts;
// jest umieszczany na końcu tabeli limitów w celu zakończenia następującej pętli
array_push($limites, $quotient);
// obliczenie podatku
$i = 0;
while ($quotient > $limites[$i])
$i++;
// ponieważ umieszczono $quotient na końcu tablicy $limites, poprzednia pętla
// nie może wykraczać poza tablicę $limites
// teraz można obliczyć podatek
return floor($revenuImposable * $coeffR[$i] - $nbParts * $coeffN[$i]);
}
?>
Plik danych data.txt (stan cywilny, dzieci, wynagrodzenie):
Pliki résultats.txt (stan cywilny, dzieci, wynagrodzenie, podatek) zawierające uzyskane wyniki:
oui:2:200000:22504
non:2:200000:33388
oui:3:200000:16400
non:3:200000:22504
oui:5:50000:0
non:0:3000000:1354938
Uwagi
- wiersz 4: nazwa pliku tekstowego zawierającego dane podatników (stan cywilny, dzieci, wynagrodzenie)
- wiersz 5: nazwa pliku tekstowego zawierającego wyniki (stan cywilny, dzieci, wynagrodzenie, podatek) obliczeń podatku
- wiersze 6–8: trzy tabele danych umożliwiające obliczenie podatku
- wiersze 11–15: otwarcie pliku z danymi podatników w trybie odczytu
- wiersze 18–22: otwarcie pliku wyników w trybie zapisu
- wiersz 25: pętla odczytu wierszy (stan cywilny, liczba dzieci, wynagrodzenie) z pliku podatników
- wiersz 27: znak końca wiersza zostaje usunięty
- wiersz 29: pobierane są składniki (stan cywilny, dzieci, wynagrodzenie) z danego wiersza
- wiersz 31: obliczany jest podatek
- wiersz 33: podatek jest zapisywany w pliku wyników
- wiersze 37–38: po pełnym przetworzeniu pliku podatników pliki są zamykane
- wiersz 44: funkcja usuwająca znak końca wiersza z wiersza $ligne. Znakiem końca wiersza jest ciąg „\r\n” w systemach Windows oraz „\n” w systemach Unix. Wynikiem jest ciąg wejściowy bez znaku końca wiersza.
- wiersze 47–48: substr($chaîne,$début,$taille) to podciąg ciągu $chaîne, zaczynający się od znaku $début i zawierający co najwyżej $taille znaków.
- wiersz 63: funkcja strtolower($chaîne) zamienia $chaîne na małe litery
- wiersz 76: array_push($tableau,$élément) dodaje $élément na końcu tablicy $tableau. Należy zauważyć, że tablica $limites została przekazana jako wartość do funkcji calculerImpot (wiersz 56: )). Dodanie tego elementu odbywa się zatem na kopii rzeczywistego parametru, który pozostaje niezmieniony.
- wiersz 84: funkcja floor($x) zwraca wartość całkowitą bezpośrednio mniejszą od $x.
4.3. Wersja z plikami tekstowymi (impots_02)
Ta nowa wersja różni się od poprzedniej jedynie tym, że dane ($limites, $coeffR, $coeffN) niezbędne do obliczenia podatku znajdują się teraz w pliku tekstowym w następującej postaci:
Plik 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
Nowa wersja ogranicza się do odczytania danych z pliku [impots.txt] w celu umieszczenia ich w trzech tabelach ($limites, $coeffR, $coeffN). W ten sposób powracamy do poprzedniego przypadku. Przedstawiamy jedynie zmiany:
<?php
// definicja stałych
$DATA = "data.txt";
$RESULTATS = "resultats.txt";
$IMPOTS = "impots.txt";
// dane niezbędne do obliczenia podatku zostały umieszczone w pliku $IMPOTS
// po jednym wierszu na tabelę w postaci
// val1:val2:val3,...
list($erreur, $limites, $coeffR, $coeffN) = getTables($IMPOTS);
// czy wystąpił błąd?
if ($erreur) {
print "$erreur\n";
exit;
}//if
// odczyt danych użytkownika
...
// koniec
exit;
// --------------------------------------------------------------------------
function cutNewLinechar($ligne) {
// usuwa się znacznik końca linii z $ligne, jeśli istnieje
...
}
// --------------------------------------------------------------------------
function calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN) {
// $marié: tak, nie
// $enfants: liczba dzieci
// $salaire: roczne wynagrodzenie
// $limites, $coeffR, $coeffN: tabele danych umożliwiające obliczenie podatku
...
}
// --------------------------------------------------------------------------
function getTables($IMPOTS) {
// $IMPOTS: nazwa pliku zawierającego dane z tabel $limites, $coeffR, $coeffN
// czy plik $IMPOTS istnieje?
if (!file_exists($IMPOTS))
return array("Le fichier $IMPOTS n'existe pas","","","");
// odczyt pliku w bloku
$tables = file($IMPOTS);
if (!$tables)
return array("Erreur lors de l'exploitation du fichier $IMPOTS","","","");
// utworzenie 3 tabel – zakłada się, że wiersze są poprawne pod względem składniowym
$limites = explode(":", cutNewLineChar($tables[0]));
$coeffR = explode(":", cutNewLineChar($tables[1]));
$coeffN = explode(":", cutNewLineChar($tables[2]));
// koniec
return array("", $limites, $coeffR, $coeffN);
}
?>
Komentarze
- wiersz 11: funkcja getTables($IMPOTS) przetwarza plik tekstowy $IMPOTS w celu wyodrębnienia z niego trzech tablic ($limites, $coeffR, $coeffN). Wynikiem są ($erreur, $limites, $coeffR, $coeffN), gdzie $erreur to komunikat o błędzie, pusty, jeśli nie wystąpił żaden błąd.
- wiersz 40: funkcja getTables($IMPOTS).
- wiersz 43: funkcja files_exists(nom_fichier) zwraca wartość logiczną true, jeśli plik nom_fichier istnieje, w przeciwnym razie zwraca wartość logiczną false.
- wiersz 46: funkcja file(nom_fichier) odczytuje cały plik tekstowy nom_fichier. Zwraca tablicę, w której każdy element stanowi wiersz pliku tekstowego. Ponieważ w tym przypadku plik impots.txt zawiera trzy wiersze tekstu, funkcja zwróci tablicę składającą się z trzech elementów.
- wiersze 50–52: wykorzystanie trzech pobranych wierszy do utworzenia trzech tablic ($limites, $coeffR, $coeffN)
Uzyskane wyniki są takie same jak w poprzedniej wersji.