Apprenez en lisant dans l'ordre

decimal et fractions — Arithmétique précise sans erreurs de float

Apprends les modules decimal et fractions de Python depuis la base. Couvre le problème 0.1 + 0.2 != 0.3 avec float, le calcul monétaire exact avec Decimal (et pourquoi tu construis Decimal à partir de chaînes), l'arithmétique avec Fraction auto-réduit, et le choix parmi les trois types numériques — avec des exercices pratiques exécutables.

Cet article couvre les deux modules pour les cas où `float` cause des problèmes. decimal.Decimal fait de l'arithmétique exacte en base 10, ce qui le rend essentiel pour les calculs monétaires ; fractions.Fraction garde le numérateur et le dénominateur sous forme d'entiers pour calculer avec des fractions réduites de façon exacte. Les deux existent pour éliminer les erreurs d'arrondi inévitables de float.

Erreurs d'arrondi de float et decimal.Decimal — N'utilise pas float pour des calculs précis

Le float de Python est représenté en interne en binaire, donc les fractions décimales comme `0.1` qui ne se divisent pas proprement en binaire portent une petite erreur d'arrondi. L'exemple le plus célèbre est `0.1 + 0.2 == 0.3` qui retourne `False`. Pour le graphique ou le calcul scientifique, l'erreur est négligeable, mais dans les sommes financières même un petit décalage devient critique.

C'est pour ça que decimal.Decimal existe. Il est représenté en interne en base 10, donc construire un Decimal depuis la chaîne "0.1" te permet de calculer sans erreur.

float vs Decimal
float0.1 + 0.2→ 0.30000000000000004erreur d'arrondiDecimalDecimal('0.1') + Decimal('0.2')→ Decimal('0.3')sans erreur
float est rapide (instructions CPU) mais introduit des erreurs d'arrondi avec des valeurs comme 0.1. Decimal utilise une représentation interne en base 10, donc il calcule exactement comme la chaîne d'entrée le dit, mais est plus lent que float. Pour le traitement de l'argent et des taxes, choisis Decimal.
from decimal import Decimal

# erreur d'arrondi de float
print(0.1 + 0.2)              # 0.30000000000000004
print(0.1 + 0.2 == 0.3)       # False  ← contre-intuitif !

# Construis Decimal depuis une chaîne (depuis un float l'erreur est héritée)
a = Decimal("0.1")
b = Decimal("0.2")
print(a + b)                  # 0.3
print(a + b == Decimal("0.3"))  # True

# Un exemple monétaire
price = Decimal("1980")
tax_rate = Decimal("0.10")
total = price * (Decimal("1") + tax_rate)
print(total)                  # 2178.00

Construis Decimal depuis une chaîne, pas depuis un float

Si tu passes un float — Decimal(0.1) — tu transmets une valeur qui porte déjà une erreur d'arrondi, donc tu finis avec un Decimal qui contient toujours l'erreur du float. Passe toujours une chaîne : Decimal("0.1"). C'est difficile à repérer dans les tests et c'est le piège classique qui produit pour la première fois en production un décalage d'un centime.

Observe d'abord l'erreur d'arrondi de float, puis passe à Decimal pour un calcul TTC exact.

① Importe Decimal depuis le module decimal.

② Calcule 0.1 + 0.2 avec float et affiche-le sous float: ◯◯ (tu devrais voir l'erreur).

③ Affiche le résultat de 0.1 + 0.2 == 0.3 sous float equal?: ◯◯ (il retourne False, contre-intuitivement).

④ Calcule 0.1 + 0.2 avec Decimal et affiche-le sous Decimal: ◯◯ (sans erreur cette fois).

⑤ Définis un prix HT de 1980 et un taux de TVA de 10% en Decimal, calcule le total TTC et affiche-le sous total: ◯◯.

Éditeur Python

Exécuter le code pour voir le résultat

fractions.Fraction — Garder les fractions comme fractions

Fraction est un type qui stocke le numérateur et le dénominateur sous forme d'entiers pour l'arithmétique. Construis-en un avec Fraction(1, 3), et les additions, soustractions et multiplications suivantes retournent un résultat de fraction réduite. En float, 1/3 est l'approximation 0.3333333333333333, mais avec Fraction il reste "un tiers" lui-même.

Fraction en bref
Fraction(1, 3)+ Fraction(1, 6)Fraction(1, 2)(auto-réduit)
Construis avec Fraction(numérateur, dénominateur) — un type ratio entier. Les résultats de + / - / * sont aussi des Fraction, et ils sont automatiquement réduits. Tu peux convertir en float avec float(f), mais ça introduit une erreur d'arrondi.
TypeReprésentation interneMeilleur usage
intEntierComptes et décomptes (sans erreur)
floatVirgule flottante binaireCalcul scientifique, graphique (rapide, avec erreur)
DecimalReprésentation en base 10Argent et taxes (quand la précision base 10 compte)
FractionNumérateur et dénominateur (entiers)Ratios et probabilités (quand tu veux une forme réduite)

Les objets Fraction exposent des attributs pour le numérateur et le dénominateur. f.numerator retourne le numérateur et f.denominator retourne le dénominateur — les deux après réduction. Par exemple, Fraction(2, 6) est normalisé en interne en Fraction(1, 3), donc .numerator est 1 et .denominator est 3.

Attribut / MéthodeSensExemple
f.numeratorNumérateurFraction(1, 3).numerator → 1
f.denominatorDénominateurFraction(1, 3).denominator → 3
float(f)Convertir en floatfloat(Fraction(1, 2)) → 0.5

Additionne deux fractions et accède aux attributs du résultat. Calcule 1/3 + 1/6 en gardant le tout en Fraction et confirme que la réponse est automatiquement réduite.

① Importe Fraction depuis le module fractions.

② Construis 1/3 et 1/6 en Fraction.

③ Additionne les deux et affiche le résultat sous sum: ◯/◯ (il devrait être auto-réduit).

④ Lis le numérateur et le dénominateur du résultat via les attributs, et affiche-les sous numerator: ◯ denominator: ◯.

⑤ Convertis le résultat en float et affiche-le sous as float: ◯.◯.

Éditeur Python

Exécuter le code pour voir le résultat
QUIZ

Vérification des connaissances

Répondez à chaque question une par une.

Question 1Quel est le choix le plus approprié quand tu ne peux pas tolérer même un décalage d'un centime dans des calculs monétaires ?

Question 2En construisant un Decimal, quelle est la bonne façon qui n'introduit pas d'erreur ?

Question 3Lequel choisis-tu quand tu veux calculer des ratios ou probabilités sous forme de fractions réduites ?