4. Exercício Prático – Versões 1 e 2
4.1. O Problema

A tabela acima permite calcular o imposto no caso simplificado de um contribuinte que tem apenas o seu salário para declarar. Conforme indicado na nota (1), o imposto calculado desta forma é o imposto antes de três mecanismos:
- o limite do quociente familiar, que se aplica a rendimentos elevados;
- o crédito fiscal e a redução fiscal que se aplicam a rendimentos baixos;
Assim, o cálculo do imposto envolve os seguintes passos [http://impotsurlerevenu.org/comprendre-le-calcul-de-l-impot/1217-calcul-de-l-impot-2019.php]:

Propomos escrever um programa para calcular o imposto de um contribuinte no caso simplificado de um contribuinte que tenha apenas o seu salário a declarar:
4.1.1. Cálculo do imposto bruto
O imposto bruto pode ser calculado da seguinte forma:
Primeiro, calculamos o número de quotas do contribuinte:
- cada progenitor contribui com 1 quota;
- Os dois primeiros filhos contribuem cada um com 1/2 parte;
- Os restantes filhos contribuem cada um com uma ação:
O número de quotas é, portanto:
- nbParts=1+nbChildren*0,5+(nbChildren-2)*0,5 se o funcionário for solteiro;
- nbParts = 2 + nbChildren * 0,5 + (nbChildren - 2) * 0,5 se for casado;
onde nbChildren é o número de filhos;
- calculamos o rendimento tributável R = 0,9 * S, em que S é o salário anual;
- O quociente familiar QF é calculado da seguinte forma: QF = R / nbParts;
- calculamos o imposto bruto I com base nos seguintes dados (2019):
9964 | 0 | 0 |
27 519 | 0,14 | 1.394,96 |
73.779 | 0,3 | 5.798 |
156 244 | 0,41 | 13 913,69 |
0 | 0,45 | 20163,45 |
Cada linha tem 3 campos: campo1, campo2, campo3. Para calcular o imposto I, procuramos a primeira linha em que QF <= campo1 e retiramos os valores dessa linha. Por exemplo, para um funcionário casado com dois filhos e um salário anual S de 50 000 euros:
Rendimento tributável: R=0,9*S=45 000
Número de partes: nbParts=2+2*0,5=3
Quociente familiar: QF=45 000/3=15 000
A primeira linha em que QF <= campo1 é a seguinte:
O Imposto I é então igual a 0,14*R – 1394,96*númeroDeAções=[0,14*45000-1394,96*3]=2115. O imposto é arredondado por defeito para o euro mais próximo.
Se a condição QF <= campo1 for verdadeira na primeira linha, então o imposto é zero.
Se QF for tal que a condição QF <= campo1 nunca seja satisfeita, então são utilizados os coeficientes da última linha. Aqui:
o que dá o imposto bruto I = 0,45*R – 20163,45*nbParts.
4.1.2. Limite do Quociente Familiar

Para determinar se o limite do quociente familiar (QF) se aplica, recalculamos o imposto bruto sem os filhos. Mais uma vez, para o trabalhador casado com dois filhos e um salário anual S de 50 000 euros:
Rendimento tributável: R = 0,9 * S = 45 000
Número de quotas: nbParts=2 (os filhos já não são contabilizados)
Quociente familiar: QF = 45 000 / 2 = 22 500
A primeira linha em que QF <= campo1 é a seguinte:
O Imposto I é, então, igual a 0,14*R – 1394,96*número de ações = [0,14*45 000 – 1394,96*2] = 3 510.
Abono máximo por filho: 1551 * 2 = 3102 euros
Imposto mínimo: 3.510 – 3.102 = 408 euros
O imposto bruto com 3 escalões fiscais, já calculado em 2.115 euros, é superior ao imposto mínimo de 408 euros, pelo que o limite familiar não se aplica neste caso.
De um modo geral, o imposto bruto é superior a (imposto1, imposto2), em que:
- [imposto1]: é o imposto bruto calculado incluindo os filhos;
- [imposto2]: é o imposto bruto calculado sem filhos e reduzido pelo crédito máximo (aqui 1.551 euros por meia quota) relativo aos filhos;
4.1.3. Cálculo da redução fiscal

Ainda para o trabalhador casado com dois filhos e um salário anual S de 50 000 euros:
O imposto bruto (2.115) da etapa anterior é inferior a 2.627 euros para um casal (1.595 euros para uma pessoa solteira): a redução fiscal aplica-se, portanto. É calculada da seguinte forma:
desconto = limiar (casal = 1.970 / solteiro = 1.196) - 0,75 * imposto bruto
desconto = 1.970 – 0,75 * 2.115 = 383,75, arredondado para 384 euros.
Novo imposto bruto = 2.115 – 384 = 1.731 euros
4.1.4. Cálculo da redução fiscal

Abaixo de um determinado limiar, é aplicada uma redução de 20% ao imposto bruto resultante dos cálculos anteriores. Em 2019, os limiares são os seguintes:
- Solteiro: 21 037 euros;
- casal: 42 074 euros; (o valor de 37 968 utilizado no exemplo acima parece estar incorreto);
Este limiar é aumentado pelo valor: 3.797 * (número de meias-partes contribuídas pelos filhos).
Mais uma vez, para o trabalhador casado com dois filhos e um salário anual S de 50 000 euros:
- o seu rendimento tributável (45 000 euros) é inferior ao limiar (42 074 + 2 × 3 797) = 49 668 euros;
- tem, portanto, direito a uma redução de 20% no seu imposto: 1.731 * 0,2 = 346,2 euros, arredondado para 347 euros;
- o imposto bruto do contribuinte passa a ser: 1.731 – 347 = 1.384 euros;
4.1.5. Cálculo do imposto líquido
O nosso cálculo termina aqui: o imposto líquido a pagar será de 1.384 euros. Na realidade, o contribuinte pode ter direito a outras deduções, nomeadamente por doações a organizações de interesse público ou geral.
4.1.6. Casos de rendimentos elevados
O nosso exemplo anterior aplica-se à maioria dos trabalhadores. No entanto, o cálculo do imposto difere para quem aufere rendimentos elevados.
4.1.6.1. Limite à redução de 10% sobre o rendimento anual
Na maioria dos casos, o rendimento tributável é calculado utilizando a fórmula: R = 0,9 × S, em que S é o salário anual. Isto é conhecido como a redução de 10%. Esta redução está limitada. Em 2019:
- não pode exceder 12 502 euros;
- não pode ser inferior a 437 euros;
Consideremos o caso de um trabalhador solteiro, sem filhos e com um salário anual de 200 000 euros:
- a redução de 10% é de 200 000 euros > 12 502 euros. Por conseguinte, o limite máximo é de 12 502 euros;
4.1.6.2. Limite do Quociente Familiar
Vamos considerar um caso em que se aplica o limite familiar mencionado no parágrafo anterior. Tomemos o caso de um casal com três filhos e um rendimento anual de 100 000 euros. Vamos rever os passos do cálculo:
- A dedução de 10% é de 10 000 euros < 12 502 euros. O rendimento tributável R é, portanto, 100 000 - 10 000 = 90 000 euros;
- O casal tem nbParts = 2 + 0,5 * 2 + 1 = 4 quotas;
- o seu quociente familiar é, portanto, QF = R / nbParts = 90 000 / 4 = 22 500 euros;
- o seu imposto bruto I1 com filhos é I1 = 0,14 × 90 000 – 1 394,96 × 4 = 7 020 euros;
- o seu imposto bruto I2 sem filhos:
- QF = 90 000 / 2 = 45 000 euros;
- I2 = 0,3 × 90 000 – 5 798 × 2 = 15 404 euros;
- a regra do limite do quociente familiar estabelece que o benefício proporcionado pelos filhos não pode exceder (1.551 × 4 meias quotas) = 6.204 euros. No entanto, neste caso, é I2 – I1 = 15.404 – 7.020 = 8.384 euros, o que é superior a 6.204 euros;
- o imposto bruto é, portanto, recalculado como I3 = I2 - 6.204 = 15.404 - 6.204 = 9.200 euros;
Este casal não receberá nem crédito fiscal nem redução, e o seu imposto final será de 9 200 euros.
4.1.7. Dados oficiais
O cálculo do imposto é complexo. Ao longo deste documento, serão realizados testes utilizando os seguintes exemplos. Os resultados provêm do simulador da autoridade fiscal [https://www3.impots.gouv.fr/simulateur/calcul_impot/2019/simplifie/index.htm]:
Contribuinte | Resultados oficiais | Resultados do algoritmo do documento |
Casal com 2 filhos e um rendimento anual de 55 555 euros | Imposto = 2.815 euros Taxa de imposto = 14% | Imposto = 2.814 euros Taxa de imposto = 14% |
Casal com 2 filhos e um rendimento anual de 50 000 euros | Imposto = 1.385 euros Crédito fiscal = 720 euros Redução = 0 euros Taxa de imposto = 14% | Imposto = 1.384 euros Dedução = 384 euros Crédito = 347 euros Taxa de imposto = 14% |
Casal com 3 filhos e um rendimento anual de 50 000 euros | Imposto = 0 euros Crédito fiscal = 384 euros Redução = 346 euros Taxa de imposto = 14% | Imposto = 0 euros Desconto = 720 euros Redução = 0 euros Taxa de imposto = 14% |
Solteiro com 2 filhos e um rendimento anual de 100 000 euros | Imposto = 19 884 euros Crédito fiscal = 0 euros Dedução = 0 euros Taxa de imposto = 41% | Imposto = 19 884 euros Sobretaxa = 4.480 euros Desconto = 0 euros Redução = 0 euros Taxa de imposto = 41% |
Solteiro com 3 filhos e um rendimento anual de 100 000 euros | Imposto = 16 782 euros Crédito fiscal = 0 euros Dedução = 0 euros Taxa de imposto = 41% | Imposto = 16 782 euros Sobretaxa = 7.176 euros Desconto = 0 euros Redução = 0 euros Taxa de imposto = 41% |
Casal com três filhos e um rendimento anual de 100 000 euros | Imposto = 9.200 euros Crédito fiscal = 0 euros Dedução = 0 euros Taxa de imposto = 30% | Imposto = 9 200 euros Sobretaxa = 2.180 euros Desconto = 0 euros Redução = 0 euros Taxa de imposto = 30% |
Casal com 5 filhos e um rendimento anual de 100 000 euros | Imposto = 4.230 euros Crédito fiscal = 0 euros Dedução = 0 euros Taxa de imposto = 14% | Imposto = 4.230 € Dedução = 0 euros Dedução = 0 euros Taxa de imposto = 14% |
Solteiro, sem filhos e rendimento anual de 100 000 euros | Imposto = 22.986 euros Crédito fiscal = 0 euros Dedução = 0 euros Taxa de imposto = 41% | Imposto = 22 986 euros Sobretaxa = 0 euros Desconto = 0 euros Redução = 0 euros Taxa de imposto = 41% |
Casal com 2 filhos e um rendimento anual de 30 000 euros | Imposto = 0 euros Crédito fiscal = 0 euros Dedução = 0 euros Taxa de imposto = 0% | Imposto = 0 euros Desconto = 0 euros Dedução = 0 euros Taxa de imposto = 0% |
Solteiro, sem filhos e rendimento anual de 200 000 euros | Imposto = 64 211 euros Crédito fiscal = 0 euros Dedução = 0 euros Taxa de imposto = 45% | Imposto = 64 210 euros Sobretaxa = 7.498 euros Desconto = 0 euros Redução = 0 euros Taxa de imposto = 45% |
Casal com 3 filhos e um rendimento anual de 200 000 euros | Imposto = 42 843 euros Crédito fiscal = 0 euros Dedução = 0 euros Taxa de imposto = 41% | Imposto = 42 842 euros Sobretaxa = 17 283 euros Desconto = 0 euros Redução = 0 euros Taxa de imposto = 41% |
No exemplo acima, a «sobretaxa» refere-se ao montante adicional pago pelos contribuintes com rendimentos elevados devido a dois fatores:
- o limite máximo de 10% de dedução do rendimento anual;
- o limite máximo do abono de família;
Este indicador não pôde ser verificado porque o simulador da autoridade fiscal não o disponibiliza.
Podemos ver que o algoritmo do documento calcula sempre o montante correto do imposto, embora com uma margem de erro de 1 euro. Esta margem de erro resulta do arredondamento. Todos os montantes monetários são arredondados para o euro superior em alguns casos e para o euro inferior noutros. Como não estava familiarizado com as regras oficiais, os montantes monetários no algoritmo do documento foram arredondados:
- para o euro superior no caso de descontos e reduções;
- para baixo, para o euro mais próximo, no caso de sobretaxas e do imposto final;
Na secção seguinte, serão realizados testes para verificar a validade dos resultados. Estes serão realizados utilizando os exemplos da tabela anterior, com uma margem de erro aceitável de 1 euro.
4.2. A estrutura do diretório do script

4.3. Versão 1
4.3.1. O Algoritmo
Apresentamos um programa inicial no qual:
- os dados necessários para calcular o imposto estão codificados no programa como matrizes e constantes;
- os dados do contribuinte (casado, filhos, salário) são armazenados num primeiro ficheiro de texto [taxpayersdata.txt];
- os resultados do cálculo do imposto (casado, filhos, salário, imposto) são armazenados num segundo ficheiro de texto [resultados.txt];
O script [version-01/main.php] é o seguinte:
<?php
// strict types for function parameters
declare(strict_types=1);
// global constants
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 of local constants
$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);
// 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
$result = calculImpot($marié, (int) $enfants, (float) $salaire, $limites, $coeffR, $coeffN);
// enter the result in the results file
$result = ["marié" => $marié, "enfants" => $enfants, "salaire" => $salaire] + $result;
fputs($résultats, \json_encode($result, JSON_UNESCAPED_UNICODE) . "\n");
// following data
}
// close files
fclose($data);
fclose($résultats);
// end
exit;
// --------------------------------------------------------------------------
function cutNewLinechar(string $ligne): string {
// 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);
}
// tAX CALCULATION
// --------------------------------------------------------------------------
function calculImpot(string $marié, int $enfants, float $salaire, array $limites, array $coeffR, array $coeffN): array {
…
// result
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 {
…
// result
return ["impôt" => $impôt, "surcôte" => $surcôte, "taux" => $coeffR[$i]];
}
// revenuImposable=annualwage-discount
// the allowance has a minimum and a maximum
function getRevenuImposable(float $salaire): float {
…
// result
return floor($revenuImposable);
}
// calculates any discount
function getDecote(string $marié, float $salaire, float $impots): float {
…
// result
return ceil($décôte);
}
// calculates any reduction
function getRéduction(string $marié, float $salaire, int $enfants, float $impots): float {
/…
// result
return ceil($réduction);
}
O ficheiro de dados taxpayersdata.txt (casado, filhos, salário):
O ficheiro results.txt (casado, filhos, salário, imposto, sobretaxa, desconto, redução, taxa de imposto) dos resultados obtidos:
Comentários
- linha 4: impomos o cumprimento rigoroso do tipo dos parâmetros da função;
- linhas 7–16: definição de todas as constantes necessárias para o cálculo do imposto;
- linha 19: o nome do ficheiro de texto que contém os dados do contribuinte (estado civil, filhos, salário);
- linha 20: o nome do ficheiro de texto que contém os resultados (casado, filhos, salário, imposto) do cálculo do imposto;
- linhas 21–23: as três matrizes de dados que definem os diferentes escalões de imposto para o cálculo do imposto;
- linhas 26–30: abrir o ficheiro de dados do contribuinte para leitura [r]. A função [fopen] devolve o valor booleano FALSE se o ficheiro não puder ser aberto;
- linhas 33–37: Abre o ficheiro de resultados no modo de escrita [w];
- linhas 40–51: loop para ler as linhas (cônjuge, filhos, rendimento) do ficheiro de dados do contribuinte;
- linha 40: a função [fgets] lê 100 caracteres e pára na primeira quebra de linha encontrada. Aqui, todas as linhas têm menos de 100 caracteres. Se for encontrada uma quebra de linha, esta é incluída na cadeia de caracteres devolvida. Quando se chega ao fim do ficheiro, a função [fgets] devolve FALSE;
- linha 42: o caractere de fim de linha é removido;
- linha 44: os componentes (casado, filhos, salário) da linha são recuperados;
- linha 46: o imposto é calculado. O resultado é devolvido como uma matriz associativa (linha 76);
- linha 48: as chaves [casado, filhos, salário] são adicionadas à matriz recuperada anteriormente;
- linha 49: o resultado é armazenado no ficheiro de resultados como uma cadeia JSON;
- linhas 53–54: assim que o ficheiro de dados do contribuinte tiver sido totalmente processado, os ficheiros são fechados;
- linha 60: a função que remove a quebra de linha de uma linha $line. A quebra de linha é a string "\r\n" em sistemas Windows, "\n" em sistemas Unix. O resultado é a string de entrada sem a sua quebra de linha.
- linhas 63-64: substr($string, $start, $size) é a subcadeia de $string que começa no caractere $start e contém, no máximo, $size caracteres;
A função [calculImpot] é a seguinte:
// constantes globales
define("PLAFOND_QF_DEMI_PART", 1551);
// calcul de l'impôt
// --------------------------------------------------------------------------
function calculImpot(string $marié, int $enfants, float $salaire, array $limites, array $coeffR, array $coeffN): array {
// $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
//
// calcul de l'impôt avec enfants
$result1 = calculImpot2($marié, $enfants, $salaire, $limites, $coeffR, $coeffN);
$impot1 = $result1["impôt"];
// calcul de l'impôt sans les enfants
if ($enfants != 0) {
$result2 = calculImpot2($marié, 0, $salaire, $limites, $coeffR, $coeffN);
$impot2 = $result2["impôt"];
// application du plafonnement du quotient familial
if ($enfants < 3) {
// $PLAFOND_QF_DEMI_PART euros pour les 2 premiers enfants
$impot2 = $impot2 - $enfants * PLAFOND_QF_DEMI_PART;
} else {
// $PLAFOND_QF_DEMI_PART euros pour les 2 premiers enfants, le double pour les suivants
$impot2 = $impot2 - 2 * PLAFOND_QF_DEMI_PART - ($enfants - 2) * 2 * PLAFOND_QF_DEMI_PART;
}
} else {
$impot2 = $impot1;
$result2 = $result1;
}
// on prend l'impôt le plus fort avec le taux et la surcôte qui vont avec
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"];
}
// calcul d'une éventuelle décôte
$décôte = getDecote($marié, $salaire, $impot);
$impot -= $décôte;
// calcul d'une éventuelle réduction d'impôts
$réduction = getRéduction($marié, $salaire, $enfants, $impot);
$impot -= $réduction;
// résultat
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 {
…
// résultat
return ["impôt" => $impôt, "surcôte" => $surcôte, "taux" => $coeffR[$i]];
}
// revenuImposable=salaireAnnuel-abattement
// l'abattement de 10 % a un min et un max
function getRevenuImposable(float $salaire): float {
…
}
// calcule une décôte éventuelle
function getDecote(string $marié, float $salaire, float $impots): float {
…
// résultat
return ceil($décôte);
}
// calcule une réduction éventuelle
function getRéduction(string $marié, float $salaire, int $enfants, float $impots): float {
…
// résultat
return ceil($réduction);
}
Comentários
- Linha 10: O imposto bruto é calculado incluindo os filhos. O resultado é devolvido na forma ["tax" => $tax, "surcharge" => $surcharge, "rate" => $coeffR[$i]], em que:
- [‘tax’]: o imposto bruto;
- [‘surcharge’]: o montante da sobretaxa, se houver. Isto aplica-se quando a dedução de 10% excede o limiar de 12 502 euros;
- [‘taxa’]: a taxa de imposto do contribuinte;
- linha 11: o imposto bruto [impot1] devido;
- linhas 13–14: se o contribuinte tiver pelo menos um filho, o cálculo do imposto é refeito utilizando os mesmos dados, mas com 0 filhos. Este segundo cálculo é necessário para determinar se a redução proporcionada pelos filhos (nbParts*coeffN) excede um determinado limiar;
- linha 15: o imposto bruto [impot2] devido;
- linhas 16–23: para o imposto bruto [impot2], os filhos são agora tidos em conta: cada 1/2 parte proporcionada pelos filhos permite uma redução de [PLAFOND_QF_DEMI_PART] euros;
- linhas 25–26: caso em que o contribuinte não tem filhos. Neste caso, o cálculo de [impot2] é desnecessário. É igual a [impot1];
- linhas 29–37: foram calculados dois impostos brutos [impot1, impot2]. A autoridade fiscal retém o mais elevado dos dois. Isto resulta num imposto bruto [impot];
- linhas 39–40: o montante bruto [tax] pode ser objeto de uma redução;
- linhas 42–43: o montante bruto [impot] pode estar sujeito a uma redução;
- linha 45: [tax] é agora o imposto líquido devido. Os resultados são devolvidos;
A função [calculImpot2] é a seguinte:
// --------------------------------------------------------------------------
function calculImpot2(string $marié, int $enfants, float $salaire, array $limites, array $coeffR, array $coeffN): array {
// $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;
}
// 1 part par enfant à partir du 3e
if ($enfants >= 3) {
// une demi-part de + pour chaque enfant à partir du 3e
$nbParts += 0.5 * ($enfants - 2);
}
// revenu imposable
$revenuImposable = getRevenuImposable($salaire);
// surcôte
$surcôte = floor($revenuImposable - 0.9 * $salaire);
// pour des pbs d'arrondi
if ($surcôte < 0) {
$surcôte = 0;
}
// quotient familial
$quotient = $revenuImposable / $nbParts;
// est mis à la fin du tableau limites pour arrêter la boucle qui suit
$limites[count($limites) - 1] = $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
$impôt = floor($revenuImposable * $coeffR[$i] - $nbParts * $coeffN[$i]);
// résultat
return ["impôt" => $impôt, "surcôte" => $surcôte, "taux" => $coeffR[$i]];
}
// revenuImposable=salaireAnnuel-abattement
// l'abattement a un min et un max
function getRevenuImposable(float $salaire): float {
// résultat
return floor($revenuImposable);
}
Comentários
- Aqui, aplicamos o cálculo do imposto utilizando a tabela de impostos progressiva;
- linha 9: strtolower($string) converte $string para minúsculas;
- linhas 10–19: cálculo do número de ações do contribuinte;
- linha 21: calculamos o rendimento tributável utilizando uma função. Com efeito, vimos que nem sempre é 0,9*RendimentoAnual. A dedução de 10% está, na verdade, limitada a 12 502 euros;
- linha 23: calcula a sobretaxa potencial se o rendimento tributável for superior a 0,9*RendimentoAnual;
- linhas 25–27: corrige o facto de que, devido a erros de arredondamento, por vezes temos [$surcharge=-1];
- linha 29: o quociente familiar;
- linhas 30–36: este quociente é utilizado para determinar a faixa de imposto do contribuinte;
- linha 40: uma vez determinada a faixa de imposto do contribuinte, o seu imposto bruto pode ser calculado. A função floor($x) devolve o número inteiro imediatamente inferior a [$x];
- linha 42: a informação calculada é devolvida;
A função [getRevenuImposable] é a seguinte:
// constantes globales
define("ABATTEMENT_DIXPOURCENT_MAX", 12502);
define("ABATTEMENT_DIXPOURCENT_MIN", 437);
// revenuImposable=salaireAnnuel-abattement
// l'abattement a un min et un max
function getRevenuImposable(float $salaire): float {
// abattement de 10% du salaire
$abattement = 0.1 * $salaire;
// cet abattement ne peut dépasser ABATTEMENT_DIXPOURCENT_MAX
if ($abattement > ABATTEMENT_DIXPOURCENT_MAX) {
$abattement = ABATTEMENT_DIXPOURCENT_MAX;
}
// l'abattement ne peut être inférieur à ABATTEMENT_DIXPOURCENT_MIN
if ($abattement < ABATTEMENT_DIXPOURCENT_MIN) {
$abattement = ABATTEMENT_DIXPOURCENT_MIN;
}
// revenu imposable
$revenuImposable = $salaire - $abattement;
// résultat
return floor($revenuImposable);
}
Comentários
- linha 5: a dedução padrão é de 10% do salário anual;
- linhas 7–9: a dedução não pode exceder a dedução máxima [ABATTEMENT_DIXPOURCENT_MAX];
- linhas 10–13: a dedução não pode ser inferior à dedução mínima [ABATTEMENT_DIXPOURCENT_MIN];
- linha 15: cálculo do rendimento tributável;
A função [getDecote] é a seguinte:
// constantes globales
define("PLAFOND_DECOTE_CELIBATAIRE", 1196);
define("PLAFOND_DECOTE_COUPLE", 1970);
define("PLAFOND_IMPOT_COUPLE_POUR_DECOTE", 2627);
define("PLAFOND_IMPOT_CELIBATAIRE_POUR_DECOTE", 1595);
// calcule une décôte éventuelle
function getDecote(string $marié, float $salaire, float $impots): float {
// au départ, une décôt nulle
$décôte = 0;
// montant maximal d'tax to get the discount
$plafondImpôtPourDécôte = $marié === "oui" ? PLAFOND_IMPOT_COUPLE_POUR_DECOTE : PLAFOND_IMPOT_CELIBATAIRE_POUR_DECOTE;
if ($impots < $plafondImpôtPourDécôte) {
// montant maximal de la décôte
$plafondDécôte = $marié === "oui" ? PLAFOND_DECOTE_COUPLE : PLAFOND_DECOTE_CELIBATAIRE;
// décôte théorique
$décôte = $plafondDécôte - 0.75 * $impots;
// la décôte ne peut dépasser le montant de l'tax
if ($décôte > $impots) {
$décôte = $impots;
}
// pas de décôte <0
if ($décôte < 0) {
$décôte = 0;
}
}
// résultat
return ceil($décôte);
}
Comentários
- linha 6: montante bruto máximo do imposto para ter direito a uma redução fiscal. Este montante difere para pessoas solteiras e casais;
- linha 7: se o contribuinte é elegível para a redução fiscal;
- linha 11: a fórmula do crédito fiscal. [taxCreditCap] é o montante máximo do crédito fiscal. Este montante máximo é calculado na linha 9. Mais uma vez, depende do estado civil do contribuinte — casado ou solteiro;
- linhas 13–15: a dedução não pode exceder o imposto bruto devido. É o que acontece, por exemplo, se [taxes] for 0 na linha 11;
- linhas 17–19: para evitar o arredondamento para -1;
A função [getReduction] é a seguinte:
// constantes globales
define("PLAFOND_REVENUS_CELIBATAIRE_POUR_REDUCTION", 21037);
define("PLAFOND_REVENUS_COUPLE_POUR_REDUCTION", 42074);
define("VALEUR_REDUC_DEMI_PART", 3797);
// calcule une réduction éventuelle
function getRéduction(string $marié, float $salaire, int $enfants, float $impots): float {
// le plafond des revenus pour avoir droit à la réduction de 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;
}
// revenu imposable
$revenuImposable = getRevenuImposable($salaire);
// réduction
$réduction = 0;
if ($revenuImposable < $plafondRevenuPourRéduction) {
// réduction de 20%
$réduction = 0.2 * $impots;
}
// résultat
return ceil($réduction);
}
Comentários
- linhas 4–10: para ter direito a uma redução fiscal, o rendimento tributável (linha 10) deve ser inferior a um limiar calculado nas linhas 4–8;
- linhas 13–16: se as condições forem cumpridas, o contribuinte tem direito a uma redução fiscal de 20% (linha 15);
4.3.2. Resultados
O ficheiro de dados taxpayersdata.txt (casado, filhos, salário):
O ficheiro results.txt (casado, filhos, salário, imposto, sobretaxa, desconto, redução, taxa de imposto) dos resultados obtidos:
Os resultados obtidos são consistentes com os obtidos utilizando o simulador da administração fiscal.
4.3.3. Conclusão
O algoritmo de cálculo do imposto, mesmo em casos considerados simples, é complexo. Não o abordaremos novamente aqui. Ao longo das diferentes versões, o seu núcleo permanecerá o mesmo, apesar de algumas alterações na apresentação. Por conseguinte, comentaremos apenas estas últimas.
4.4. Versão 2
4.4.1. Alterações
Na versão anterior, os dados necessários para calcular o imposto estavam codificados como constantes e matrizes. Este método deve ser evitado. Na nova versão, estes dados são externalizados para um ficheiro JSON:

O conteúdo do ficheiro [taxadmindata.json] é o seguinte:
{
"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
}
A nova versão [version-02/main.php] é a seguinte:
<?php
// strict adherence to declared function parameter types
declare (strict_types=1);
// definition of constants
$TAXPAYERSDATA = "taxpayersdata.txt";
$RESULTATS = "resultats.txt";
$TAXADMINDATA = "taxadmindata.json";
// retrieve the contents of the tax data file
$fileContents = \file_get_contents($TAXADMINDATA);
$erreur = FALSE;
// mistake?
if (!$fileContents) {
// we note the error
$erreur = TRUE;
$message = "Le fichier des données [$TAXADMINDATA] n'existe pas";
}
if (!$erreur) {
// retrieve the jSON code from the configuration file in an associative array
$taxAdminData = \json_decode($fileContents, true);
// mistake?
if (!$taxAdminData) {
// we note the error
$erreur = TRUE;
$message = "Le fichier de données jSON [$TAXADMINDATA] n'a pu être exploité correctement";
}
}
// mistake?
if ($erreur) {
print "$message\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";
// output
exit;
}
// opening taxpayer data file
$taxpayersdata = fopen($TAXPAYERSDATA, "r");
if (!$taxpayersdata) {
print "Impossible d'ouvrir le fichier des contribuables [$TAXPAYERSDATA]\n";
// output
exit;
}
// use the current line of the data file
while ($ligne = fgets($taxpayersdata, 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
$result = calculImpot($taxAdminData, $marié, (int) $enfants, (int) $salaire);
// enter the result in the results file
$result = ["marié" => $marié, "enfants" => $enfants, "salaire" => $salaire] + $result;
fputs($résultats, \json_encode($result, JSON_UNESCAPED_UNICODE) . "\n");
// following data
}
// close files
fclose($taxpayersdata);
fclose($résultats);
// end
exit;
// --------------------------------------------------------------------------
function cutNewLinechar(string $ligne) {
…
// end
return($ligne);
}
// tAX CALCULATION
// --------------------------------------------------------------------------
function calculImpot(array $taxAdminData, string $marié, int $enfants, float $salaire) {
// $marié : yes, no
// $enfants : number of children
// $salaire: annual salary
// $taxAdminData: tax administration data
//
// tax calculation with children
$result1 = calculImpot2($taxAdminData, $marié, $enfants, $salaire);
$impot1 = $result1["impôt"];
// tax calculation without children
if ($enfants != 0) {
$result2 = calculImpot2($taxAdminData, $marié, 0, $salaire);
$impot2 = $result2["impôt"];
// application of the family allowance ceiling
if ($enfants < 3) {
// $PLAFOND_QF_DEMI_PART euros for the first 2 children
$impot2 = $impot2 - $enfants * $taxAdminData["PLAFOND_QF_DEMI_PART"];
} else {
// $PLAFOND_QF_DEMI_PART euros for the first 2 children, double for subsequent children
$impot2 = $impot2 - 2 * $taxAdminData["PLAFOND_QF_DEMI_PART"] - ($enfants - 2) * 2 * $taxAdminData["PLAFOND_QF_DEMI_PART"];
}
} else {
$impot2 = $impot1;
$result2 = $result1;
}
// we take the highest tax with the rate and surcharge that go with it
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"];
}
// calculation of any discount
$décôte = getDecote($taxAdminData, $marié, $salaire, $impot);
$impot -= $décôte;
// calculation of any tax reduction
$réduction = getRéduction($taxAdminData, $marié, $salaire, $enfants, $impot);
$impot -= $réduction;
// result
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é : yes, no
…
// result
return ["impôt" => $impôt, "surcôte" => $surcôte, "taux" => $coeffR[$i]];
}
// revenuImposable=annualwage-discount
// the allowance has a minimum and a maximum
function getRevenuImposable(array $taxAdminData, float $salaire): float {
…
// result
return floor($revenuImposable);
}
// calculates any discount
function getDecote(array $taxAdminData, string $marié, float $salaire, float $impots): float {
…
// result
return ceil($décôte);
}
// calculates any reduction
function getRéduction(array $taxAdminData, string $marié, float $salaire, int $enfants, float $impots): float {
…
// result
return ceil($réduction);
}
Comentários
- linhas 11–19: tentamos ler o conteúdo do ficheiro JSON denominado [TAXADMINDATA];
- linhas 21–30: se o ficheiro JSON foi lido com sucesso, o seu conteúdo é descodificado para a matriz associativa [$taxAdminData];
- linhas 32–36: se ocorreu um erro em qualquer uma das duas operações anteriores, é exibida uma mensagem de erro na consola e o programa é interrompido;
- A diferença em relação à versão 01 é que, aqui, os dados da administração fiscal (matrizes e constantes) são armazenados na matriz associativa [$taxAdminData], enquanto na versão 01 eram armazenados em matrizes e constantes globais. É a natureza global destas constantes que distingue as duas versões:
- na versão 01, as constantes eram conhecidas em todas as funções de [main.php];
- para obter o mesmo resultado na versão 02, a matriz associativa [$taxAdminData] deve ser passada como parâmetro a todas as funções (linhas 83, 129, 138, 145, 152);
- cada função na versão 02 deve utilizar o conteúdo da matriz [$taxAdminData];
- Linhas 83–126: Na função [calculateTax], onde anteriormente eram utilizadas constantes globais ou as matrizes [limits, coeffR, coeffN], agora utilizamos o conteúdo da matriz [$taxAdminData] passada como parâmetro (linhas 99, 102);
- Todas as outras funções são reescritas da mesma forma;
Os resultados obtidos são os mesmos que os obtidos na versão anterior.
4.4.2. Conclusão
A versão 02 é muito mais flexível do que a versão 01. Em 2020, o algoritmo de cálculo de impostos será provavelmente o mesmo que em 2019. Apenas as faixas de imposto e as constantes de cálculo terão mudado. Bastará então atualizar o ficheiro [taxadmindata.json]. Com a versão 01, é necessário aceder ao código para modificar as faixas de imposto e as constantes de cálculo. No entanto, é provável que as pessoas que precisam de alterar os valores das faixas de imposto e das constantes de cálculo não tenham acesso ao código do algoritmo.