Comment effectuer des calculs décimaux précis en Python

Vous devez effectuer des calculs précis avec des nombres décimaux et vous ne voulez pas des petites erreurs qui se produisent naturellement avec les flottants.

Un problème bien connu des nombres à virgule flottante est qu’ils ne peuvent pas représenter avec précision toutes les décimales de base 10. De plus, même de simples calculs mathématiques introduisent de petites erreurs. Par exemple:

>>> a = 4.2
>>> b = 2.1
>>> a + b
6.300000000000001
>>> (a + b) == 6.3
False
>>>

Ces erreurs sont une “caractéristique” du CPU sous-jacent et de l’arithmétique IEEE 754 effectuée par son unité à virgule flottante.

Puisque le type de données flottantes de Python stocke les données en utilisant la représentation native, il n’y a rien que vous puissiez faire pour éviter de telles erreurs si vous écrivez votre code en utilisant des nombres flottants.

Si vous voulez plus de précision (et êtes prêt à sacrifier certaines performances), vous pouvez utiliser le module décimal:

>>> from decimal import Decimal
>>> a = Decimal('4.2')
>>> b = Decimal('2.1')
>>> a + b
Decimal('6.3')
>>> print(a + b)
6.3
>>> (a + b) == Decimal('6.3')
True
>>>

À première vue, cela peut sembler un peu bizarre (c.-à-d., spécifier des nombres comme chaînes de caractères). Cependant, les objets décimaux fonctionnent de toutes les façons que vous vous attendez à ce qu’ils fonctionnent (supportant toutes les opérations mathématiques habituelles, etc.).

Si vous les imprimez ou les utilisez dans les fonctions de formatage de chaînes de caractères, elles ressemblent à des nombres normaux.

Une caractéristique majeure du module decimal est qu’elle vous permet de contrôler différents aspects des calculs, y compris le nombre de chiffres et l’arrondi. Pour ce faire, vous créez un contexte local et modifiez ses paramètres. Par exemple:

>>> from decimal import localcontext
>>> a = Decimal('1.3')
>>> b = Decimal('1.7')
>>> print(a / b)
0.7647058823529411764705882353
>>> with localcontext() as ctx:
...     ctx.prec = 3
...     print(a / b)
...
0.765
>>> with localcontext() as ctx:
...     ctx.prec = 50
...     print(a / b)
...
0.76470588235294117647058823529411764705882352941176
>>>

Le module decimal implémente la “Spécification générale d’arithmétique décimale d’IBM”.

Les nouveaux arrivants en Python pourraient être enclins à utiliser le module decimal pour contourner les problèmes de précision perçus avec le type de données flottantes. Cependant, il est très important de comprendre votre domaine d’application.

Si vous travaillez avec des problèmes de science ou d’ingénierie, d’infographie ou la plupart des choses de nature scientifique, il est simplement plus courant d’utiliser le type à virgule flottante normal.

D’une part, très peu de choses dans le monde réel sont mesurées avec les 17 chiffres de précision que fournissent les flottants. Ainsi, les petites erreurs introduites dans les calculs n’ont tout simplement pas d’importance.

Deuxièmement, la performance des flottants natifs est beaucoup plus rapide, ce qui est important si vous effectuez un grand nombre de calculs.

Cela dit, vous ne pouvez pas ignorer complètement les erreurs. Les mathématiciens ont passé beaucoup de temps à étudier divers algorithmes, et certains traitent mieux les erreurs que d’autres.

Vous devez également être un peu prudent avec les effets dus à des choses telles que l’annulation soustractive et l’addition de grands et petits nombres ensemble. Par exemple:

>>> nums = [1.23e+18, 1, -1.23e+18]
>>> sum(nums)    # Notice how 1 disappears
0.0
>>>

Ce dernier exemple peut être traité en utilisant une implémentation plus précise dans math.fsum():

>>> import math
>>> math.fsum(nums)
1.0
>>>

Cependant, pour d’autres algorithmes, il faut vraiment étudier l’algorithme et comprendre ses propriétés de propagation des erreurs.

Cela dit, le module decimal est surtout utilisé dans les programmes qui touchent des domaines tels que les finances. Dans de tels programmes, il est extrêmement ennuyeux de voir de petites erreurs se glisser dans le calcul.

Ainsi, le module decimal permet d’éviter cela. Il est également courant de rencontrer des objets décimaux lorsque Python s’interface à nouveau avec des bases de données, en particulier lors de l’accès aux données financières.

LAISSER UN COMMENTAIRE

Please enter your comment!
Please enter your name here