4. Anwendungsaufgabe – Versionen 1 und 2
4.1. Die Aufgabe

Anhand der obigen Tabelle lässt sich die Steuer im vereinfachten Fall eines Steuerpflichtigen berechnen, der lediglich sein Gehalt anzugeben hat. Wie in Anmerkung (1) angegeben, handelt es sich bei der so berechneten Steuer um die Steuer vor Berücksichtigung dreier Mechanismen:
- der Begrenzung des Familienquotienten, die bei hohen Einkommen greift;
- dem Steuerabschlag und der Steuerermäßigung, die bei niedrigen Einkommen zum Tragen kommen;
Die Berechnung der Steuer umfasst somit die folgenden Schritte [http://impotsurlerevenu.org/comprendre-le-calcul-de-l-impot/1217-calcul-de-l-impot-2019.php]:

Wir wollen ein Programm schreiben, mit dem sich die Steuer eines Steuerpflichtigen im vereinfachten Fall berechnen lässt, in dem dieser lediglich sein Gehalt anzugeben hat:
4.1.1. Berechnung der Bruttosteuer
Die Bruttosteuer lässt sich wie folgt berechnen:
Zunächst wird die Anzahl der Anteile des Steuerpflichtigen berechnet:
- Jeder Elternteil bringt 1 Anteil mit;
- die ersten beiden Kinder bringen jeweils einen halben Anteil mit;
- die folgenden Kinder bringen jeweils einen Anteil mit:
Die Anzahl der Anteile beträgt somit:
- nbParts = 1 + nbEnfants * 0,5 + (AnzahlKinder – 2) * 0,5, wenn der Arbeitnehmer unverheiratet ist;
- AnzahlAnteile = 2 + AnzahlKinder * 0,5 + (AnzahlKinder – 2) * 0,5, wenn er verheiratet ist;
wobei nbEnfants die Anzahl seiner Kinder ist;
- das zu versteuernde Einkommen R wird berechnet als R = 0,9 * S, wobei S das Jahresgehalt ist;
- man berechnet den Familienquotienten QF = R / nbParts;
- Die Bruttosteuer I wird anhand der folgenden Daten (2019) berechnet:
9964 | 0 | 0 |
27519 | 0,14 | 1394,96 |
73779 | 0,3 | 5798 |
156.244 | 0,41 | 13.913,69 |
0 | 0,45 | 20163,45 |
Jede Zeile enthält drei Felder: champ1, champ2, champ3. Um die Steuer I zu berechnen, wird die erste Zeile gesucht, in der QF <= Feld 1 gilt, und man übernimmt die Werte dieser Zeile. Beispielsweise für einen verheirateten Arbeitnehmer mit zwei Kindern und einem Jahresgehalt S von 50.000 Euro:
Steuerpflichtiges Einkommen: R = 0,9 * S = 45.000
Anzahl der Anteile: nbParts = 2 + 2 * 0,5 = 3
Familienquotient: QF = 45.000 / 3 = 15.000
Die erste Zeile, in der QF <= Feld1 gilt, lautet wie folgt:
Die Steuer I beträgt somit 0,14*R – 1394,96*nbParts=[0,14*45000-1394,96*3]=2115. Die Steuer wird auf den nächsten ganzen Euro abgerundet.
Gilt bereits in der ersten Zeile die Bedingung QF <= Feld1, so beträgt die Steuer null.
Wenn QF so ist, dass die Bedingung QF <= Feld1 niemals erfüllt ist, dann werden die Koeffizienten der letzten Zeile verwendet. Hier:
was die Bruttosteuer I = 0,45 * R – 20163,45 * nbParts ergibt.
4.1.2. Obergrenze für den Familienquotienten

Um festzustellen, ob die Obergrenze für den Familienquotienten QF gilt, wird die Bruttosteuer erneut ohne die Kinder berechnet. Wiederum für den verheirateten Arbeitnehmer mit zwei Kindern und einem Jahresgehalt S von 50.000 Euro:
Steuerpflichtiges Einkommen: R = 0,9 * S = 45.000
Anzahl der Anteile: nbParts = 2 (die Kinder werden nicht mehr berücksichtigt)
Familienquotient: QF = 45.000 / 2 = 22.500
Die erste Zeile, in der QF <= Feld1 gilt, lautet wie folgt:
Die Steuer I beträgt somit 0,14*R – 1394,96*nbParts = [0,14*45000-1394,96*2] = 3510.
Maximaler Kinderfreibetrag: 1551 * 2 = 3102 Euro
Mindeststeuer: 3510 – 3102 = 408 Euro
Die bereits berechnete Bruttosteuer mit 3 Anteilen in Höhe von 2115 Euro liegt über der Mindeststeuer von 408 Euro, daher findet die Familienobergrenze hier keine Anwendung.
Im Allgemeinen gilt: Die Bruttosteuer ist größer als (Steuer1, Steuer2), wobei:
- [impôt1]: die mit den Kindern berechnete Bruttosteuer;
- [impôt2]: ist die Bruttosteuer, die ohne Kinder berechnet und um den maximalen Kinderfreibetrag (hier 1551 Euro pro Halbanteil) verringert wurde;
4.1.3. Berechnung des Abschlags

Weiterhin für den verheirateten Arbeitnehmer mit zwei Kindern und einem Jahresgehalt S von 50.000 Euro:
Die Bruttosteuer (2.115) aus dem vorherigen Schritt liegt unter 2.627 Euro für ein Ehepaar (1.595 Euro für einen Alleinstehenden): Daher kommt der Abschlag zur Anwendung. Er ergibt sich aus folgender Berechnung:
Abzug = Schwellenwert (Ehepaar = 1.970 / Alleinstehender = 1.196) – 0,75 * Bruttosteuer
Abzug = 1970 – 0,75 * 2115 = 383,75, gerundet auf 384 Euro.
Neue Bruttosteuer = 2115 – 384 = 1731 Euro
4.1.4. Berechnung der Steuerermäßigung

Unterhalb einer bestimmten Schwelle wird eine Ermäßigung von 20 % auf die aus den vorangegangenen Berechnungen resultierende Bruttosteuer gewährt. Im Jahr 2019 gelten folgende Schwellenwerte:
- Alleinstehend: 21.037 Euro;
- Paar: 42.074 Euro; (die im obigen Beispiel verwendete Zahl 37.968 scheint falsch zu sein);
Dieser Schwellenwert wird um den Wert 3.797 * (Anzahl der durch die Kinder mitgebrachten halben Steueranteile) erhöht.
Beziehen wir uns weiterhin auf den verheirateten Arbeitnehmer mit zwei Kindern und einem Jahresgehalt S von 50.000 Euro:
- Sein zu versteuerndes Einkommen (45.000 Euro) liegt unter dem Schwellenwert (42.074 + 2 * 3.797) = 49.668 Euro;
- er hat daher Anspruch auf eine Ermäßigung seiner Steuer um 20 %: 1731 * 0,2 = 346,2 Euro, gerundet auf 347 Euro;
- Die Bruttosteuer des Steuerpflichtigen beträgt somit: 1.731 – 347 = 1.384 Euro;
4.1.5. Berechnung der Nettosteuer
Unsere Berechnung endet hier: Die zu zahlende Nettosteuer beträgt 1384 Euro. In der Praxis kann der Steuerpflichtige weitere Ermäßigungen in Anspruch nehmen, insbesondere für Spenden an gemeinnützige oder öffentliche Einrichtungen.
4.1.6. Fallbeispiel: Hohe Einkommen
Unser vorangegangenes Beispiel entspricht den meisten Fällen von Arbeitnehmern. Bei hohen Einkommen sieht die Steuerberechnung jedoch anders aus.
4.1.6.1. Obergrenze für den 10-prozentigen Freibetrag auf das Jahreseinkommen
In den meisten Fällen ergibt sich das zu versteuernde Einkommen aus der Formel: R = 0,9 * S, wobei S das Jahresgehalt ist. Dies wird als 10-Prozent-Ermäßigung bezeichnet. Diese Ermäßigung ist begrenzt. Im Jahr 2019:
- darf sie 12.502 Euro nicht überschreiten;
- sie darf nicht unter 437 Euro liegen;
Nehmen wir den Fall eines unverheirateten Arbeitnehmers ohne Kinder mit einem Jahresgehalt von 200.000 Euro:
- Die 10-prozentige Kürzung beträgt 200.000 Euro > 12.502 Euro. Sie wird daher auf 12.502 Euro herabgesetzt;
4.1.6.2. Obergrenze für den Familienquotienten
Betrachten wir einen Fall, in dem die im Absatz „Link“ dargestellte Obergrenze für den Familienquotienten zum Tragen kommt. Nehmen wir den Fall eines Paares mit drei Kindern und einem Jahreseinkommen von 100.000 Euro. Gehen wir die Berechnungsschritte noch einmal durch:
- Der Freibetrag von 10 % beträgt 10.000 Euro < 12.502 Euro. Das zu versteuernde Einkommen R beträgt somit 100.000 – 10.000 = 90.000 Euro;
- das Paar hat nbParts = 2 + 0,5 × 2 + 1 = 4 Anteile;
- sein Familienquotient beträgt somit QF = R / nbParts = 90.000 / 4 = 22.500 Euro;
- seine Bruttosteuer I1 mit Kindern beträgt I1 = 0,14 * 90.000 – 1.394,96 * 4 = 7.020 Euro;
- seine Bruttosteuer I2 ohne Kinder:
- QF = 90.000 / 2 = 45.000 Euro;
- I2 = 0,3 * 90.000 – 5.798 * 2 = 15.404 Euro;
- Die Regel zur Begrenzung des Familienquotienten besagt, dass der durch die Kinder erzielte Gewinn (1551 × 4 halbe Anteile) = 6204 Euro nicht überschreiten darf. Hier beträgt er jedoch I2-I1 = 15404 – 7020 = 8384 Euro und liegt somit über 6204 Euro;
- die Bruttosteuer wird daher neu berechnet als I3 = I2-6204 = 15.404 – 6.204 = 9.200 Euro;
Dieses Ehepaar erhält weder einen Freibetrag noch einen Steuerabzug, und seine endgültige Steuerbelastung beträgt 9.200 Euro.
4.1.7. Offizielle Zahlen
Die Berechnung der Steuer ist komplex. Im gesamten Dokument werden die Berechnungen anhand der folgenden Beispiele durchgeführt. Die Ergebnisse stammen aus dem Simulator der Steuerbehörde [https://www3.impots.gouv.fr/simulateur/calcul_impot/2019/simplifie/index.htm]:
Steuerpflichtiger | Offizielle Ergebnisse | Ergebnisse des Algorithmus aus dem Dokument |
Paar mit 2 Kindern und einem Jahreseinkommen von 55555 Euro | Steuer = 2815 Euro Steuersatz = 14 % | Steuer = 2.814 Euro Steuersatz = 14 % |
Paar mit 2 Kindern und einem Jahreseinkommen von 50.000 Euro | Steuer = 1.385 Euro Steuerermäßigung = 720 Euro Ermäßigung = 0 Euro Steuersatz = 14 % | Steuer = 1.384 Euro Abzug = 384 Euro Ermäßigung = 347 Euro Steuersatz = 14 % |
Paar mit 3 Kindern und einem Jahreseinkommen von 50.000 Euro | Steuer = 0 Euro Abzug = 384 Euro Steuerermäßigung = 346 Euro Steuersatz = 14 % | Steuer = 0 Euro Abzug = 720 Euro Abzug = 0 Euro Steuersatz = 14 % |
Alleinstehend mit 2 Kindern und einem Jahreseinkommen von 100.000 Euro | Steuer = 19.884 Euro Abzug = 0 Euro Steuerermäßigung = 0 Euro Steuersatz = 41 % | Steuer = 19.884 Euro Zuschlag = 4.480 Euro Abzug = 0 Euro Ermäßigung = 0 Euro Steuersatz = 41 % |
Alleinstehend mit 3 Kindern und einem Jahreseinkommen von 100.000 Euro | Steuer = 16.782 Euro Abzug = 0 Euro Steuerermäßigung = 0 Euro Steuersatz = 41 % | Steuer = 16.782 Euro Zuschlag = 7.176 Euro Abschlag = 0 Euro Ermäßigung = 0 Euro Steuersatz = 41 % |
Paar mit 3 Kindern und einem Jahreseinkommen von 100.000 Euro | Steuer = 9.200 Euro Abzug = 0 Euro Steuerermäßigung = 0 Euro Steuersatz = 30 % | Steuer = 9.200 Euro Zuschlag = 2.180 Euro Abschlag = 0 Euro Ermäßigung = 0 Euro Steuersatz = 30 % |
Paar mit 5 Kindern und einem Jahreseinkommen von 100.000 Euro | Steuer = 4.230 Euro Abzug = 0 Euro Steuerermäßigung = 0 Euro Steuersatz = 14 % | Steuer = 4.230 Euro Abzug = 0 Euro Ermäßigung = 0 Euro Steuersatz = 14 % |
Alleinstehend, ohne Kinder und mit einem Jahreseinkommen von 100.000 Euro | Steuer = 22.986 Euro Abzug = 0 Euro Steuerermäßigung = 0 Euro Steuersatz = 41 % | Steuer = 22.986 Euro Zuschlag = 0 Euro Abzug = 0 Euro Ermäßigung = 0 Euro Steuersatz = 41 % |
Paar mit 2 Kindern und einem Jahreseinkommen von 30.000 Euro | Steuer = 0 Euro Abzug = 0 Euro Steuerermäßigung = 0 Euro Steuersatz = 0 % | Steuer = 0 Euro Abschlag = 0 Euro Ermäßigung = 0 Euro Steuersatz = 0 % |
Alleinstehend, ohne Kinder und mit einem Jahreseinkommen von 200.000 Euro | Steuer = 64.211 Euro Abzug = 0 Euro Steuerermäßigung = 0 Euro Steuersatz = 45 % | Steuer = 64.210 Euro Zuschlag = 7.498 Euro Abschlag = 0 Euro Ermäßigung = 0 Euro Steuersatz = 45 % |
Paar mit 3 Kindern und einem Jahreseinkommen von 200.000 Euro | Steuer = 42.843 Euro Abzug = 0 Euro Steuerermäßigung = 0 Euro Steuersatz = 41 % | Steuer = 42.842 Euro Zuschlag = 17.283 Euro Abzug = 0 Euro Ermäßigung = 0 Euro Steuersatz = 41 % |
Oben wird als Zuschlag bezeichnet, was Personen mit hohem Einkommen aufgrund zweier Phänomene zusätzlich zahlen:
- die Begrenzung des Freibetrags von 10 % auf das Jahreseinkommen;
- die Begrenzung des Familienquotienten;
Dieser Indikator konnte nicht überprüft werden, da er im Simulator der Steuerbehörde nicht angegeben ist.
Es zeigt sich, dass der Algorithmus des Dokuments jedes Mal eine korrekte Steuer angibt, allerdings mit einer Fehlermarge von 1 Euro. Diese Fehlermarge resultiert aus Rundungen. Alle Geldbeträge werden mal auf den nächsten höheren Euro, mal auf den nächsten niedrigeren Euro gerundet. Da mir die offiziellen Regeln nicht bekannt waren, wurden die Geldbeträge im Algorithmus des Dokuments wie folgt gerundet:
- bei Preisnachlässen und Rabatten auf den nächsten höheren Euro;
- auf den nächsten Euro nach unten bei Aufschlägen und der Endsteuer;
Im weiteren Verlauf werden Tests durchgeführt, um die Gültigkeit der Ergebnisse zu überprüfen. Diese werden anhand der Beispiele aus der vorstehenden Tabelle mit einer akzeptierten Fehlermarge von 1 Euro durchgeführt.
4.2. Die Skriptstruktur

4.3. Version 1
4.3.1. Der Algorithmus
Wir stellen ein erstes Programm vor, bei dem:
- die für die Steuerberechnung erforderlichen Daten fest im Code in Form von Tabellen und Konstanten hinterlegt sind;
- die Daten der Steuerzahler (verheiratet, Kinder, Gehalt) in einer ersten Textdatei [taxpayersdata.txt] gespeichert sind;
- die Ergebnisse der Steuerberechnung (verheiratet, Kinder, Gehalt, Steuer) in einer zweiten Textdatei [resultats.txt] gespeichert sind;
Das Skript [version-01/main.php] lautet wie folgt:
<?php
// Strenge Typen für Funktionsparameter
declare(strict_types=1);
// globale Konstanten
define("PLAFOND_QF_DEMI_PART", 1551);
define("PLAFOND_REVENUS_CELIBATAIRE_POUR_REDUCTION", 21037);
define("PLAFOND_REVENUS_COUPLE_POUR_REDUCTION", 42074);
define("VALEUR_REDUC_DEMI_PART", 3797);
define("PLAFOND_DECOTE_CELIBATAIRE", 1196);
define("PLAFOND_DECOTE_COUPLE", 1970);
define("PLAFOND_IMPOT_COUPLE_POUR_DECOTE", 2627);
define("PLAFOND_IMPOT_CELIBATAIRE_POUR_DECOTE", 1595);
define("ABATTEMENT_DIXPOURCENT_MAX", 12502);
define("ABATTEMENT_DIXPOURCENT_MIN", 437);
// Definition lokaler Konstanten
$DATA = "taxpayersdata.txt";
$RESULTATS = "resultats.txt";
$limites = array(9964, 27519, 73779, 156244, 0);
$coeffR = array(0, 0.14, 0.3, 0.41, 0.45);
$coeffN = array(0, 1394.96, 5798, 13913.69, 20163.45);
// Daten auslesen
$data = fopen($DATA, "r");
if (!$data) {
print "Impossible d'ouvrir en lecture le fichier des données [$DATA]\n";
exit;
}
// Ergebnisdatei öffnen
$résultats = fopen($RESULTATS, "w");
if (!$résultats) {
print "Impossible de créer le fichier des résultats [$RESULTATS]\n";
exit;
}
// Auswertung der aktuellen Zeile der Datendatei
while ($ligne = fgets($data, 100)) {
// Eventuelles Zeilenendezeichen wird entfernt
$ligne = cutNewLineChar($ligne);
// die drei Felder „verheiratet:Kinder:Gehalt“ werden abgerufen, die $ligne bilden
list($marié, $enfants, $salaire) = explode(",", $ligne);
// Die Steuer wird berechnet
$result = calculImpot($marié, (int) $enfants, (float) $salaire, $limites, $coeffR, $coeffN);
// Das Ergebnis wird in die Ergebnisdatei eingetragen
$result = ["marié" => $marié, "enfants" => $enfants, "salaire" => $salaire] + $result;
fputs($résultats, \json_encode($result, JSON_UNESCAPED_UNICODE) . "\n");
// nächster Datensatz
}
// Die Dateien werden geschlossen
fclose($data);
fclose($résultats);
// Ende
exit;
// --------------------------------------------------------------------------
function cutNewLinechar(string $ligne): string {
// Das Zeilenendezeichen von $ligne wird entfernt, falls vorhanden
$L = strlen($ligne); // Zeilenzahl
while (substr($ligne, $L - 1, 1) === "\n" or substr($ligne, $L - 1, 1) === "\r") {
$ligne = substr($ligne, 0, $L - 1);
$L--;
}
// Ende
return($ligne);
}
// Steuerberechnung
// --------------------------------------------------------------------------
function calculImpot(string $marié, int $enfants, float $salaire, array $limites, array $coeffR, array $coeffN): array {
…
// Ergebnis
return ["impôt" => floor($impot), "surcôte" => $surcôte, "décôte" => $décôte, "réduction" => $réduction, "taux" => $taux];
}
// --------------------------------------------------------------------------
function calculImpot2(string $marié, int $enfants, float $salaire, array $limites, array $coeffR, array $coeffN): array {
…
// Ergebnis
return ["impôt" => $impôt, "surcôte" => $surcôte, "taux" => $coeffR[$i]];
}
// revenuImposable=Jahresgehalt-Freibetrag
// Der Freibetrag hat einen Mindest- und einen Höchstwert
function getRevenuImposable(float $salaire): float {
…
// Ergebnis
return floor($revenuImposable);
}
// berechnet einen eventuellen Abschlag
function getDecote(string $marié, float $salaire, float $impots): float {
…
// Ergebnis
return ceil($décôte);
}
// berechnet einen eventuellen Abschlag
function getRéduction(string $marié, float $salaire, int $enfants, float $impots): float {
/…
// Ergebnis
return ceil($réduction);
}
Die Datendatei taxpayersdata.txt (verheiratet, Kinder, Gehalt):
Die Datei résultats.txt (verheiratet, Kinder, Gehalt, Steuern, Zuschlag, Abschlag, Ermäßigung, Steuersatz) mit den erzielten Ergebnissen:
Anmerkungen
- Zeile 4: Es wird die strikte Einhaltung des Typs der Funktionsparameter erzwungen;
- Zeilen 7–16: Definition aller für die Steuerberechnung erforderlichen Konstanten;
- Zeile 19: Der Name der Textdatei, die die Daten der Steuerpflichtigen enthält (verheiratet, Kinder, Gehalt);
- Zeile 20: Name der Textdatei, die die Ergebnisse (Familienstand, Kinder, Gehalt, Steuer) der Steuerberechnung enthält;
- Zeilen 21–23: die drei Datentabellen, die die verschiedenen Steuerklassen für die Steuerberechnung definieren;
- Zeilen 26–30: Öffnen der Steuerzahlerdatei im Lesemodus mit [r]. Die Funktion [fopen] gibt den Booleschen Wert FALSE zurück, wenn das Öffnen nicht möglich war;
- Zeilen 33–37: Öffnen der Ergebnisdatei zum Schreiben mit [w];
- Zeilen 40–51: Schleife zum Einlesen der Zeilen (Ehepartner, Kinder, Gehalt) aus der Steuerzahlerdatei;
- Zeile 40: Die Funktion [fgets] liest 100 Zeichen und stoppt beim ersten gefundenen Zeilenendezeichen. Hier sind alle Zeilen kürzer als 100 Zeichen. Wenn ein Zeilenendezeichen gefunden wurde, wird es in die zurückgegebene Zeichenkette aufgenommen. Wenn das Ende der Datei erreicht ist, gibt die Funktion [fgets] den Wert FALSE zurück;
- Zeile 42: Das Zeilenendezeichen wird entfernt;
- Zeile 44: Die Komponenten (Ehepartner, Kinder, Gehalt) der Zeile werden extrahiert;
- Zeile 46: Die Steuer wird berechnet. Das Ergebnis wird in Form eines assoziativen Arrays zurückgegeben (Zeile 76);
- Zeile 48: Dem zuvor abgerufenen Array werden die Schlüssel [marié, enfants, salaire] hinzugefügt;
- Zeile 49: Das Ergebnis wird in der Ergebnisdatei in Form einer Zeichenkette jSON gespeichert;
- Zeilen 53–54: Sobald die Steuerzahlerdatei vollständig ausgewertet ist, werden die Dateien geschlossen;
- Zeile 60: Die Funktion, die das Zeilenendezeichen aus einer Zeile $ligne entfernt. Das Zeilenendezeichen ist die Zeichenkette „\r\n“ auf Windows-Systemen, „\n“ auf Unix-Systemen. Das Ergebnis ist die Eingabezeichenkette ohne ihr Zeilenendezeichen.
- Zeilen 63–64: substr($chaîne, $début,$taille) ist die Teilzeichenfolge von $chaîne, die beim Zeichen $début beginnt und höchstens $taille Zeichen umfasst;
Die Funktion [calculImpot] lautet wie folgt:
// globale Konstanten
define("PLAFOND_QF_DEMI_PART", 1551);
// Steuerberechnung
// --------------------------------------------------------------------------
function calculImpot(string $marié, int $enfants, float $salaire, array $limites, array $coeffR, array $coeffN): array {
// $marié: ja, nein
// $enfants: Anzahl der Kinder
// $salaire: Jahresgehalt
// $limites, $coeffR, $coeffN: Datentabellen zur Berechnung der Steuer
//
// Steuerberechnung mit Kindern
$result1 = calculImpot2($marié, $enfants, $salaire, $limites, $coeffR, $coeffN);
$impot1 = $result1["impôt"];
// Steuerberechnung ohne Kinder
if ($enfants != 0) {
$result2 = calculImpot2($marié, 0, $salaire, $limites, $coeffR, $coeffN);
$impot2 = $result2["impôt"];
// Anwendung der Obergrenze für den Familienquotienten
if ($enfants < 3) {
// $PLAFOND_QF_DEMI_PART Euro für die ersten beiden Kinder
$impot2 = $impot2 - $enfants * PLAFOND_QF_DEMI_PART;
} else {
// $PLAFOND_QF_DEMI_PART Euro für die ersten beiden Kinder, das Doppelte für die folgenden
$impot2 = $impot2 - 2 * PLAFOND_QF_DEMI_PART - ($enfants - 2) * 2 * PLAFOND_QF_DEMI_PART;
}
} else {
$impot2 = $impot1;
$result2 = $result1;
}
// Es gilt der höchste Steuerbetrag mit dem entsprechenden Steuersatz und dem dazugehörigen Aufschlag
if ($impot1 > $impot2) {
$impot = $impot1;
$taux = $result1["taux"];
$surcôte = $result1["surcôte"];
} else {
$surcôte = $impot2 - $impot1 + $result2["surcôte"];
$impot = $impot2;
$taux = $result2["taux"];
}
// Berechnung eines eventuellen Steuerabzugs
$décôte = getDecote($marié, $salaire, $impot);
$impot -= $décôte;
// Berechnung einer möglichen Steuerermäßigung
$réduction = getRéduction($marié, $salaire, $enfants, $impot);
$impot -= $réduction;
// Ergebnis
return ["impôt" => floor($impot), "surcôte" => $surcôte, "décôte" => $décôte, "réduction" => $réduction, "taux" => $taux];
}
// --------------------------------------------------------------------------
function calculImpot2(string $marié, int $enfants, float $salaire, array $limites, array $coeffR, array $coeffN): array {
…
// Ergebnis
return ["impôt" => $impôt, "surcôte" => $surcôte, "taux" => $coeffR[$i]];
}
// revenuImposable=Jahresgehalt-Freibetrag
// Der Freibetrag von 10 % hat einen Mindest- und einen Höchstwert
function getRevenuImposable(float $salaire): float {
…
}
// berechnet einen eventuellen Abschlag
function getDecote(string $marié, float $salaire, float $impots): float {
…
// Ergebnis
return ceil($décôte);
}
// berechnet eine eventuelle Kürzung
function getRéduction(string $marié, float $salaire, int $enfants, float $impots): float {
…
// Ergebnis
return ceil($réduction);
}
Anmerkungen
- Zeile 10: Die Bruttosteuer wird unter Berücksichtigung der Kinder berechnet. Das Ergebnis liegt in der Form ["impôt" => $impôt, "surcôte" => $surcôte, "taux" => $coeffR[$i]] vor, wobei:
- [‘impôt’]: die Bruttosteuer;
- [‘surcôte’]: den Betrag des Zuschlags, falls vorhanden. Dieser fällt an, wenn der Freibetrag von 10 % die Schwelle von 12.502 Euro überschreitet;
- [‘taux’]: den Steuersatz des Steuerpflichtigen;
- Zeile 11: die zu zahlende Bruttosteuer [impot1];
- Zeilen 13–14: Hat der Steuerpflichtige mindestens ein Kind, wird die Steuerberechnung mit denselben Daten, jedoch unter der Annahme von 0 Kindern, erneut durchgeführt. Diese zweite Berechnung ist erforderlich, um festzustellen, ob die durch die Kinder bedingte Ermäßigung (nbParts*coeffN) einen bestimmten Schwellenwert überschreitet;
- Zeile 15: die zu zahlende Bruttosteuer [impot2];
- Zeilen 16–23: Bei der Bruttosteuer [impot2] werden nun die Kinder berücksichtigt: Jeder durch die Kinder bedingte halbe Anteil ermöglicht eine Ermäßigung um [PLAFOND_QF_DEMI_PART] Euro;
- Zeilen 25–26: Fall, in dem der Steuerpflichtige keine Kinder hat. In diesem Fall ist die Berechnung von [impot2] überflüssig. Der Betrag entspricht [impot1];
- Zeilen 29–37: Es wurden zwei Bruttosteuerbeträge berechnet: [impot1, impot2]. Die Steuerbehörde berücksichtigt den höheren der beiden Beträge. Daraus ergibt sich ein Bruttosteuerbetrag von [impot];
- Zeilen 39–40: Der Bruttobetrag [impot] kann gekürzt werden;
- Zeilen 42–43: Der Bruttobetrag [impot] kann gekürzt werden;
- Zeile 45: [impot] ist nun die zu zahlende Nettosteuer. Die Ergebnisse werden ausgegeben;
Die Funktion [calculImpot2] lautet wie folgt:
// --------------------------------------------------------------------------
function calculImpot2(string $marié, int $enfants, float $salaire, array $limites, array $coeffR, array $coeffN): array {
// $marié: ja, nein
// $enfants: Anzahl der Kinder
// $salaire: Jahresgehalt
// $limites, $coeffR, $coeffN: Datentabellen zur Berechnung der Steuer
//
// Anzahl der Anteile
$marié = strtolower($marié);
if ($marié === "oui") {
$nbParts = $enfants / 2 + 2;
} else {
$nbParts = $enfants / 2 + 1;
}
// 1 Anteil pro Kind ab dem dritten
if ($enfants >= 3) {
// ein halber Anteil zusätzlich für jedes Kind ab dem dritten
$nbParts += 0.5 * ($enfants - 2);
}
// steuerpflichtiges Einkommen
$revenuImposable = getRevenuImposable($salaire);
// Zuschlag
$surcôte = floor($revenuImposable - 0.9 * $salaire);
// bei Rundungsproblemen
if ($surcôte < 0) {
$surcôte = 0;
}
// Familienquotient
$quotient = $revenuImposable / $nbParts;
// wird am Ende der Grenzwertetabelle eingefügt, um die folgende Schleife zu beenden
$limites[count($limites) - 1] = $quotient;
// Steuerberechnung
$i = 0;
while ($quotient > $limites[$i]) {
$i++;
}
// da $quotient am Ende des Arrays $limites platziert wurde, die vorherige Schleife
// darf nicht über das Array $limites hinausgehen
// Nun kann die Steuer berechnet werden
$impôt = floor($revenuImposable * $coeffR[$i] - $nbParts * $coeffN[$i]);
// Ergebnis
return ["impôt" => $impôt, "surcôte" => $surcôte, "taux" => $coeffR[$i]];
}
// revenuImposable = Jahresgehalt – Freibetrag
// Der Freibetrag hat einen Mindest- und einen Höchstwert
function getRevenuImposable(float $salaire): float {
// Ergebnis
return floor($revenuImposable);
}
Anmerkungen
- Hier wird die Steuerberechnung nach dem sogenannten progressiven Steuertarif angewendet;
- Zeile 9: strtolower($chaîne) wandelt $chaîne in Kleinbuchstaben um;
- Zeilen 10–19: Berechnung der Anzahl der Anteile des Steuerpflichtigen;
- Zeile 21: Das zu versteuernde Einkommen wird mithilfe einer Funktion berechnet. Wie wir gesehen haben, beträgt es nicht immer 0,9*revenusAnnuels. Der Freibetrag von 10 % ist nämlich auf 12.502 Euro begrenzt;
- Zeile 23: Berechnung des eventuellen Zuschlags, falls das zu versteuernde Einkommen höher ist als 0,9*revenusAnnuels;
- Zeilen 25–27: Behebt das Problem, dass aufgrund von Rundungsfehlern manchmal [$surcôte=-1] angezeigt wird;
- Zeile 29: der Familienquotient;
- Zeilen 30–36: Anhand dieses Quotienten lässt sich die Steuerklasse des Steuerpflichtigen ermitteln;
- Zeile 40: Sobald die Steuerklasse des Steuerpflichtigen ermittelt wurde, kann seine Bruttosteuer berechnet werden. Die Funktion floor($x) liefert den ganzzahligen Wert, der unmittelbar unter [$x] liegt;
- Zeile 42: Die berechneten Informationen werden ausgegeben;
Die Funktion [getRevenuImposable] lautet wie folgt:
// globale Konstanten
define("ABATTEMENT_DIXPOURCENT_MAX", 12502);
define("ABATTEMENT_DIXPOURCENT_MIN", 437);
// revenuImposable=Jahresgehalt-Freibetrag
// Der Freibetrag hat einen Mindest- und einen Höchstwert
function getRevenuImposable(float $salaire): float {
// Freibetrag in Höhe von 10 % des Gehalts
$abattement = 0.1 * $salaire;
// Dieser Freibetrag darf ABATTEMENT_DIXPOURCENT_MAX nicht überschreiten
if ($abattement > ABATTEMENT_DIXPOURCENT_MAX) {
$abattement = ABATTEMENT_DIXPOURCENT_MAX;
}
// Der Freibetrag darf nicht unter ABATTEMENT_DIXPOURCENT_MIN liegen
if ($abattement < ABATTEMENT_DIXPOURCENT_MIN) {
$abattement = ABATTEMENT_DIXPOURCENT_MIN;
}
// steuerpflichtiges Einkommen
$revenuImposable = $salaire - $abattement;
// Ergebnis
return floor($revenuImposable);
}
Anmerkungen
- Zeile 5: Der normale Freibetrag beträgt 10 % des Jahresgehalts;
- Zeilen 7–9: Der Freibetrag darf den Höchstfreibetrag [ABATTEMENT_DIXPOURCENT_MAX] nicht überschreiten;
- Zeilen 10–13: Der Freibetrag darf nicht unter dem Mindestfreibetrag [ABATTEMENT_DIXPOURCENT_MIN] liegen;
- Zeile 15: Berechnung des steuerpflichtigen Einkommens;
Die Funktion [getDecote] lautet wie folgt:
// globale Konstanten
define("PLAFOND_DECOTE_CELIBATAIRE", 1196);
define("PLAFOND_DECOTE_COUPLE", 1970);
define("PLAFOND_IMPOT_COUPLE_POUR_DECOTE", 2627);
define("PLAFOND_IMPOT_CELIBATAIRE_POUR_DECOTE", 1595);
// berechnet einen eventuellen Abschlag
function getDecote(string $marié, float $salaire, float $impots): float {
// Anfangswert: Null-Abschlag
$décôte = 0;
// Höchststeuerbetrag, bei dem der Abschlag gewährt wird
$plafondImpôtPourDécôte = $marié === "oui" ? PLAFOND_IMPOT_COUPLE_POUR_DECOTE : PLAFOND_IMPOT_CELIBATAIRE_POUR_DECOTE;
if ($impots < $plafondImpôtPourDécôte) {
// Maximaler Abschlagbetrag
$plafondDécôte = $marié === "oui" ? PLAFOND_DECOTE_COUPLE : PLAFOND_DECOTE_CELIBATAIRE;
// theoretischer Abschlag
$décôte = $plafondDécôte - 0.75 * $impots;
// Der Abschlag darf den Steuerbetrag nicht überschreiten
if ($décôte > $impots) {
$décôte = $impots;
}
// kein Abschlag <0
if ($décôte < 0) {
$décôte = 0;
}
}
// Ergebnis
return ceil($décôte);
}
Anmerkungen
- Zeile 6: Höchstbetrag der Bruttosteuer, ab dem ein Steuerfreibetrag gewährt wird. Dieser Betrag ist für Alleinstehende und Paare unterschiedlich;
- Zeile 7: ob der Steuerpflichtige Anspruch auf den Steuerfreibetrag hat;
- Zeile 11: Die Formel für den Steuerabzug. [plafondDécôte] ist der Höchstbetrag des Steuerabzugs. Dieser Höchstbetrag wird in Zeile 9 berechnet. Auch hier hängt er von der Situation des Steuerpflichtigen ab, ob verheiratet oder alleinstehend;
- Zeilen 13–15: Der Steuerfreibetrag darf die zu zahlende Bruttosteuer nicht übersteigen. Dies ist beispielsweise der Fall, wenn [impots] in Zeile 11 den Wert 0 hat;
- Zeilen 17–19: Um eine Rundung auf -1 zu vermeiden;
Die Funktion [getRéduction] lautet wie folgt:
// globale Konstanten
define("PLAFOND_REVENUS_CELIBATAIRE_POUR_REDUCTION", 21037);
define("PLAFOND_REVENUS_COUPLE_POUR_REDUCTION", 42074);
define("VALEUR_REDUC_DEMI_PART", 3797);
// berechnet eine eventuelle Ermäßigung
function getRéduction(string $marié, float $salaire, int $enfants, float $impots): float {
// die Einkommensobergrenze für den Anspruch auf die Ermäßigung von 20 %
$plafondRevenuPourRéduction = $marié === "oui" ? PLAFOND_REVENUS_COUPLE_POUR_REDUCTION : PLAFOND_REVENUS_CELIBATAIRE_POUR_REDUCTION;
$plafondRevenuPourRéduction += $enfants * VALEUR_REDUC_DEMI_PART;
if ($enfants > 2) {
$plafondRevenuPourRéduction += ($enfants - 2) * VALEUR_REDUC_DEMI_PART;
}
// steuerpflichtiges Einkommen
$revenuImposable = getRevenuImposable($salaire);
// Ermäßigung
$réduction = 0;
if ($revenuImposable < $plafondRevenuPourRéduction) {
// 20 % Rabatt
$réduction = 0.2 * $impots;
}
// Ergebnis
return ceil($réduction);
}
Anmerkungen
- Zeilen 4–10: Um Anspruch auf eine Steuerermäßigung zu haben, muss das zu versteuernde Einkommen (Zeile 10) unter einer in den Zeilen 4–8 berechneten Obergrenze liegen;
- Zeilen 13–16: Erfüllt der Steuerpflichtige die Voraussetzungen, hat er Anspruch auf eine Steuerermäßigung von 20 % (Zeile 15);
4.3.2. Ergebnisse
Die Datendatei taxpayersdata.txt (verheiratet, Kinder, Gehalt):
Die Datei résultats.txt (verheiratet, Kinder, Gehalt, Steuer, Zuschlag, Abschlag, Ermäßigung, Steuersatz) der erzielten Ergebnisse:
Die erzielten Ergebnisse stimmen mit denen überein, die mit dem Simulator der Steuerbehörde ermittelt wurden.
4.3.3. Fazit
Der Algorithmus zur Steuerberechnung ist selbst in vermeintlich einfachen Fällen komplex. Wir werden nicht weiter darauf eingehen. Im Laufe der Versionen bleibt sein Kern trotz einiger Änderungen in der Darstellung derselbe. Wir werden daher nur auf diese Änderungen eingehen.
4.4. Version 2
4.4.1. Die Änderungen
In der vorherigen Version waren die für die Steuerberechnung erforderlichen Daten fest als Konstanten und Tabellen codiert. Diese Vorgehensweise ist zu vermeiden. In der neuen Version werden diese Daten in eine Datei mit dem Namen jSON ausgelagert:

Der Inhalt der Datei [taxadmindata.json] lautet wie folgt:
{
"limites": [9964, 27519, 73779, 156244, 0],
"coeffR": [0, 0.14, 0.3, 0.41, 0.45],
"coeffN": [0, 1394.96, 5798, 13913.69, 20163.45],
"PLAFOND_QF_DEMI_PART": 1551,
"PLAFOND_REVENUS_CELIBATAIRE_POUR_REDUCTION": 21037,
"PLAFOND_REVENUS_COUPLE_POUR_REDUCTION": 42074,
"VALEUR_REDUC_DEMI_PART": 3797,
"PLAFOND_DECOTE_CELIBATAIRE": 1196,
"PLAFOND_DECOTE_COUPLE": 1970,
"PLAFOND_IMPOT_COUPLE_POUR_DECOTE": 2627,
"PLAFOND_IMPOT_CELIBATAIRE_POUR_DECOTE": 1595,
"ABATTEMENT_DIXPOURCENT_MAX": 12502,
"ABATTEMENT_DIXPOURCENT_MIN": 437
}
Die neue Version [version-02/main.php] lautet wie folgt:
<?php
// Strikte Einhaltung der deklarierten Typen der Funktionsparameter
declare (strict_types=1);
// Definition von Konstanten
$TAXPAYERSDATA = "taxpayersdata.txt";
$RESULTATS = "resultats.txt";
$TAXADMINDATA = "taxadmindata.json";
// Der Inhalt der Steuerdatendatei wird abgerufen
$fileContents = \file_get_contents($TAXADMINDATA);
$erreur = FALSE;
// Fehler?
if (!$fileContents) {
// Der Fehler wird vermerkt
$erreur = TRUE;
$message = "Le fichier des données [$TAXADMINDATA] n'existe pas";
}
if (!$erreur) {
// Der Code jSON wird aus der Konfigurationsdatei in ein assoziatives Array geladen
$taxAdminData = \json_decode($fileContents, true);
// Fehler?
if (!$taxAdminData) {
// Der Fehler wird vermerkt
$erreur = TRUE;
$message = "Le fichier de données jSON [$TAXADMINDATA] n'a pu être exploité correctement";
}
}
// Fehler?
if ($erreur) {
print "$message\n";
exit;
}
// Ergebnisdatei öffnen
$résultats = fopen($RESULTATS, "w");
if (!$résultats) {
print "Impossible de créer le fichier des résultats [$RESULTATS]\n";
// Ausgabe
exit;
}
// Öffnen der Steuerzahlerdatei
$taxpayersdata = fopen($TAXPAYERSDATA, "r");
if (!$taxpayersdata) {
print "Impossible d'ouvrir le fichier des contribuables [$TAXPAYERSDATA]\n";
// Ausgabe
exit;
}
// Die aktuelle Zeile der Datendatei wird verarbeitet
while ($ligne = fgets($taxpayersdata, 100)) {
// Eventuelles Zeilenendezeichen wird entfernt
$ligne = cutNewLineChar($ligne);
// Die drei Felder „verheiratet:Kinder:Gehalt“, die $ligne bilden, werden abgerufen
list($marié, $enfants, $salaire) = explode(",", $ligne);
// Die Steuer wird berechnet
$result = calculImpot($taxAdminData, $marié, (int) $enfants, (int) $salaire);
// Das Ergebnis wird in die Ergebnisdatei geschrieben
$result = ["marié" => $marié, "enfants" => $enfants, "salaire" => $salaire] + $result;
fputs($résultats, \json_encode($result, JSON_UNESCAPED_UNICODE) . "\n");
// Nächster Datensatz
}
// Dateien werden geschlossen
fclose($taxpayersdata);
fclose($résultats);
// Ende
exit;
// --------------------------------------------------------------------------
function cutNewLinechar(string $ligne) {
…
// Ende
return($ligne);
}
// Steuerberechnung
// --------------------------------------------------------------------------
function calculImpot(array $taxAdminData, string $marié, int $enfants, float $salaire) {
// $marié: ja, nein
// $enfants: Anzahl der Kinder
// $salaire: Jahresgehalt
// $taxAdminData: Daten der Steuerbehörde
//
// Steuerberechnung mit Kindern
$result1 = calculImpot2($taxAdminData, $marié, $enfants, $salaire);
$impot1 = $result1["impôt"];
// Steuerberechnung ohne Kinder
if ($enfants != 0) {
$result2 = calculImpot2($taxAdminData, $marié, 0, $salaire);
$impot2 = $result2["impôt"];
// Anwendung der Obergrenze für den Familienquotienten
if ($enfants < 3) {
// $PLAFOND_QF_DEMI_PART Euro für die ersten beiden Kinder
$impot2 = $impot2 - $enfants * $taxAdminData["PLAFOND_QF_DEMI_PART"];
} else {
// $PLAFOND_QF_DEMI_PART Euro für die ersten beiden Kinder, das Doppelte für die folgenden
$impot2 = $impot2 - 2 * $taxAdminData["PLAFOND_QF_DEMI_PART"] - ($enfants - 2) * 2 * $taxAdminData["PLAFOND_QF_DEMI_PART"];
}
} else {
$impot2 = $impot1;
$result2 = $result1;
}
// Es gilt der höchste Steuerbetrag mit dem entsprechenden Steuersatz und dem dazugehörigen Aufschlag
if ($impot1 > $impot2) {
$impot = $impot1;
$taux = $result1["taux"];
$surcôte = $result1["surcôte"];
} else {
$surcôte = $impot2 - $impot1 + $result2["surcôte"];
$impot = $impot2;
$taux = $result2["taux"];
}
// Berechnung eines eventuellen Steuerabzugs
$décôte = getDecote($taxAdminData, $marié, $salaire, $impot);
$impot -= $décôte;
// Berechnung einer möglichen Steuerermäßigung
$réduction = getRéduction($taxAdminData, $marié, $salaire, $enfants, $impot);
$impot -= $réduction;
// Ergebnis
return ["impôt" => floor($impot), "surcôte" => $surcôte, "décôte" => $décôte, "réduction" => $réduction, "taux" => $taux];
}
// --------------------------------------------------------------------------
function calculImpot2(array $taxAdminData, string $marié, int $enfants, float $salaire) {
// $marié: ja, nein
…
// Ergebnis
return ["impôt" => $impôt, "surcôte" => $surcôte, "taux" => $coeffR[$i]];
}
// revenuImposable=Jahresgehalt-Freibetrag
// Der Freibetrag hat einen Mindest- und einen Höchstwert
function getRevenuImposable(array $taxAdminData, float $salaire): float {
…
// Ergebnis
return floor($revenuImposable);
}
// berechnet einen eventuellen Abschlag
function getDecote(array $taxAdminData, string $marié, float $salaire, float $impots): float {
…
// Ergebnis
return ceil($décôte);
}
// berechnet einen eventuellen Abschlag
function getRéduction(array $taxAdminData, string $marié, float $salaire, int $enfants, float $impots): float {
…
// Ergebnis
return ceil($réduction);
}
Anmerkungen
- Zeilen 11–19: Es wird versucht, den Inhalt der Datei „jSON“ mit dem Namen „[TAXADMINDATA]“ zu lesen;
- Zeilen 21–30: Wenn das Einlesen der Datei „jSON“ erfolgreich war, wird ihr Inhalt in das assoziative Array „[$taxAdminData]“ dekodiert;
- Zeilen 32–36: Wenn bei einem der beiden vorangegangenen Vorgänge ein Fehler aufgetreten ist, wird eine Fehlermeldung in die Konsole geschrieben und das Programm beendet;
- Der Unterschied zur Version 01 besteht darin, dass sich die Daten (Arrays und Konstanten) der Steuerbehörde hier im assoziativen Array [$taxAdminData] befinden, während sie in Version 01 in globalen Arrays und Konstanten gespeichert waren. Es ist die Globalität dieser Konstanten, die den Unterschied zwischen den beiden Versionen ausmacht:
- In Version 01 waren die Konstanten in allen Funktionen von [main.php] bekannt;
- um in Version 02 das gleiche Ergebnis zu erzielen, muss das assoziative Array [$taxAdminData] als Parameter an alle Funktionen übergeben werden (Zeilen 83, 129, 138, 145, 152);
- jede Funktion der Version 02 muss den Inhalt des Arrays [$taxAdminData] verwenden;
- Zeilen 83–126: In der Funktion [calculerImpot] wird an den Stellen, an denen zuvor globale Konstanten oder die Arrays [limites, coeffR, coeffN] verwendet wurden, nun der Inhalt des als Parameter übergebenen Arrays [$taxAdminData] verwendet (Zeilen 99, 102);
- alle anderen Funktionen werden auf die gleiche Weise umgeschrieben;
Die erzielten Ergebnisse entsprechen denen der vorherigen Version.
4.4.2. Fazit
Die Version 02 ist wesentlich flexibler als die Version 01. Im Jahr 2020 wird der Algorithmus zur Steuerberechnung wahrscheinlich derselbe sein wie im Jahr 2019. Lediglich die Steuerklassen und die Berechnungskonstanten werden sich geändert haben. Es reicht dann aus, die Datei [taxadmindata.json] zu aktualisieren. Bei Version 01 muss man im Quellcode die Steuerklassen und die Berechnungskonstanten ändern. Es ist jedoch wahrscheinlich, dass diejenigen, die die Werte der Steuerklassen und der Berechnungskonstanten ändern müssen, keinen Zugriff auf den Quellcode des Algorithmus haben.