3 votes

Imprimer des nombres à virgule flottante avec une précision variable

Je veux imprimer des nombres à virgule flottante qui contiennent une précision variable.

J'ai plusieurs numéros tels que :

0.634564644534135499
0.0005462007746487777
0.028820785252590582
0.0018751147995774936
0.0075146048125540816
0.00046670455

Je veux obtenir les mêmes chiffres en sortie en utilisant print. Je sais que le nombre de décimales peut être fixé à l'aide de la fonction print("{:.19f}".format(0.0005462007746487777)) mais je ne veux pas que le nombre de décimales soit fixe. Puisque des nombres différents auront des décimales différentes

Code

#!/usr/bin/env python3

number_1=0.634564644534135499
number_2=0.0005462007746487777
number_3=0.028820785252590582
number_4=0.0018751147995774936
number_5=0.0075146048125540816
number_6=0.00046670455

print("Number 1: ",number_1)
print("Number 2: ",number_2)
print("Number 3: ",number_3)
print("Number 4: ",number_4)
print("Number 5: ",number_5)
print("Number 6: ",number_6)

Sortie réelle :

Number 1:  0.6345646445341355
Number 2:  0.0005462007746487777
Number 3:  0.028820785252590582
Number 4:  0.0018751147995774936
Number 5:  0.0075146048125540816
Number 6:  0.00046670455

Sortie requise :

Number 1: 0.634564644534135499
Number 2: 0.0005462007746487777
Number 3: 0.028820785252590582
Number 4: 0.0018751147995774936
Number 5: 0.0075146048125540816
Number 6: 0.00046670455

Ce que je ne comprends pas, c'est pourquoi Numéro 2 (qui a une plus grande précision) est imprimé correctement mais Numéro 1 perd sa précision ?

3voto

juanpa.arrivillaga Points 35811

Fondamentalement, ce dont vous avez besoin n'est pas possible avec float qui sont essentiellement des enveloppes autour des doublons C, donc des nombres à virgule flottante de 64 bits.

Il y a plusieurs choses qui se passent ici. Il y a le problème fondamental du mappage d'une entrée littérale décimale dans votre code source :

0.634564644534135499

à une représentation réelle de la machine, qui est no décimal, mais binaire.

En raison des contraintes inhérentes au format à virgule flottante de 64 bits, plusieurs entrées décimales seront mises en correspondance avec la même représentation sous-jacente :

>>> 0.634564644534135499 == 0.6345646445341355
True

Ce qui est en fait ni de ceux-là, la décimale exacte est en fait :

>>> import decimal
>>> decimal.Decimal(0.6345646445341355)
Decimal('0.6345646445341355246227976749651134014129638671875')
>>> decimal.Decimal(0.634564644534135499)
Decimal('0.6345646445341355246227976749651134014129638671875')

Qu'est-ce que effectivement imprimé quand vous avez naïvement print(some_float) sera une représentation qui est garantie de revenir au même flottant qui l'a produit si vous l'entrez comme un littéral décimal flottant. En effet, depuis Python 3.1 CPython utilise l'algorithme de David Gray pour trouver les le plus court une telle représentation qui préserve la valeur.

Ainsi, comme c'est souvent le cas lorsque l'on rencontre des problèmes dus à la limitation inhérente à la technologie de la float essayez d'utiliser decimal.Decimal . Rappelez-vous que l'entrée doit être un chaîne de caractères . Le script suivant :

import decimal
number_1 = decimal.Decimal('0.634564644534135499')
number_2 = decimal.Decimal('0.0005462007746487777')
number_3 = decimal.Decimal('0.028820785252590582')
number_4 = decimal.Decimal('0.0018751147995774936')
number_5 = decimal.Decimal('0.0075146048125540816')
number_6 = decimal.Decimal('0.00046670455')

print("Number 1: ",number_1)
print("Number 2: ",number_2)
print("Number 3: ",number_3)
print("Number 4: ",number_4)
print("Number 5: ",number_5)
print("Number 6: ",number_6)

Imprimés :

Number 1:  0.634564644534135499
Number 2:  0.0005462007746487777
Number 3:  0.028820785252590582
Number 4:  0.0018751147995774936
Number 5:  0.0075146048125540816
Number 6:  0.00046670455

1voto

Keshav Biyani Points 81

Voici donc une image de référence d'un numéro en général (tirée de ce lien sur le web) https://www.log2base2.com/number-system/float-to-binary-conversion.html ) : Any floating point number

Python utilise chaque bit pour stocker la partie intégrale et la partie fractionnaire et utilise 64 bits pour stocker une valeur à virgule flottante. Ainsi, si la partie intégrale (valeur absolue) est élevée, cela signifie automatiquement que la partie fractionnaire aura moins de bits pour le stockage.

Dans les exemples que vous avez fournis, puisque chaque valeur a une partie intégrale égale à 0, la comparaison peut être effectuée entièrement sur la partie fractionnaire.

Dans ce cas, nous allons donc nous contenter de regarder les valeurs qui se trouvent dans les parties fractionnaires.

Dans le premier exemple (0,634564644534135499), le nombre de valeurs après la virgule est inférieur à celui du deuxième cas (0,0005462007746487777), mais le nombre de bits requis est plus élevé dans le premier cas que dans le deuxième. Ainsi, la valeur stockée sera arrondie pour s'assurer que le nombre de bits est conforme aux exigences de python.

Pour changer cela, je pense que l'on peut stocker les valeurs entre guillemets sous la forme d'une chaîne. Cela fonctionnera, mais si l'on suppose que vous obtiendrez les données d'un autre endroit, je ne suis pas sûr que ce soit très bon :

number_1="0.634564644534135499"
# number_3=0.028820785252590582
# number_4=0.0018751147995774936
# number_5=0.0075146048125540816
# number_6=0.00046670455

print("Number 1: ",number_1)
# print("Number 2: ",number_2)

Une autre solution consiste à utiliser decimal.Decimal('0.634564644534135499'). Si je n'ai pas répondu à votre question, à savoir pourquoi cela se produit de cette façon, dites-le moi s'il vous plaît, je vais essayer de mieux vous expliquer.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X