web-dev-qa-db-fra.com

Limiter les flottants à deux décimales

Je veux que a soit arrondi à 13.95 .

>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999

La fonction round ne fonctionne pas comme prévu.

1449
kevin

Vous rencontrez le ancien problème avec des nombres en virgule flottante que tous les nombres ne peuvent pas être représentés exactement. La ligne de commande ne fait que vous montrer la totalité de la fiche en virgule flottante.

Avec une représentation en virgule flottante, votre version arrondie est le même nombre. Étant donné que les ordinateurs sont binaires, ils stockent les nombres à virgule flottante sous forme d’entier, puis le divisent par une puissance de deux; 13,95 seront donc représentés de la même façon que 125650429603636838/(2 ** 53).

Les nombres en double précision ont une précision de 53 bits (16 chiffres) et les nombres flottants normaux ont une précision de 24 bits (8 chiffres). Le type à virgule flottante dans Python utilise la double précision pour stocker les valeurs.

Par exemple,

  >>> 125650429603636838/(2**53)
  13.949999999999999

  >>> 234042163/(2**24)
  13.949999988079071

  >>> a=13.946
  >>> print(a)
  13.946
  >>> print("%.2f" % a)
  13.95
  >>> round(a,2)
  13.949999999999999
  >>> print("%.2f" % round(a,2))
  13.95
  >>> print("{0:.2f}".format(a))
  13.95
  >>> print("{0:.2f}".format(round(a,2)))
  13.95
  >>> print("{0:.15f}".format(round(a,2)))
  13.949999999999999

Si vous ne recherchez que deux décimales (pour afficher une valeur monétaire, par exemple), vous disposez de deux meilleurs choix:

  1. Utilisez des nombres entiers et stockez les valeurs en cents, pas en dollars, puis divisez-les par 100 pour les convertir en dollars.
  2. Ou utilisez un nombre à virgule fixe tel que décimal .
1441
Rex Logan

Il existe de nouvelles spécifications de format, Spécification de format de chaîne Mini-langage :

Vous pouvez faire la même chose que:

"{0:.2f}".format(13.949999999999999)

Notez que ce qui précède renvoie une chaîne. Pour obtenir un flottant, enveloppez-vous simplement avec float(...):

float("{0:.2f}".format(13.949999999999999))

Notez que le wrapping avec float() ne change rien:

>>> x = 13.949999999999999999
>>> x
13.95
>>> g = float("{0:.2f}".format(x))
>>> g
13.95
>>> x == g
True
>>> h = round(x, 2)
>>> h
13.95
>>> x == h
True
516
Xolve

La round() intégrée fonctionne parfaitement dans Python 2.7 ou version ultérieure.

Exemple:

>>> round(14.22222223, 2)
14.22

Départ la documentation .

244
chribsen

Je pense que l’approche la plus simple consiste à utiliser la fonction format().

Par exemple:

a = 13.949999999999999
format(a, '.2f')

13.95

Cela produit un nombre flottant sous forme de chaîne arrondie à deux décimales.

133
grant zukowski

La plupart des nombres ne peuvent pas être représentés exactement dans des flottants. Si vous voulez arrondir le nombre parce que c'est ce que votre formule mathématique ou votre algorithme nécessite, vous voulez utiliser rond. Si vous souhaitez simplement limiter l'affichage à une certaine précision, n'utilisez même pas round et formatez-le simplement avec cette chaîne. (Si vous souhaitez l'afficher avec une autre méthode d'arrondi et qu'il y en a des tonnes, vous devez mélanger les deux approches.)

>>> "%.2f" % 3.14159
'3.14'
>>> "%.2f" % 13.9499999
'13.95'

Et enfin, bien que peut-être le plus important, si vous voulez exact maths, vous ne voulez pas du tout de flotteurs. L'exemple habituel consiste à gérer de l'argent et à stocker des "cents" sous forme de nombre entier.

90
Roger Pate

Utilisation

print"{:.2f}".format(a)

au lieu de

print"{0:.2f}".format(a)

Ce dernier risque d’entraîner des erreurs lors de la sortie de plusieurs variables (voir les commentaires).

83
Alexey Antonenko

Essayez le code ci-dessous:

>>> a = 0.99334
>>> a = int((a * 100) + 0.5) / 100.0 # Adding 0.5 rounds it up
>>> print a
0.99
70
ax003d

Avec Python <3 (par exemple 2.6 ou 2.7), il existe deux façons de le faire.

# Option one 
older_method_string = "%.9f" % numvar

# Option two (note ':' before the '.9f')
newer_method_string = "{:.9f}".format(numvar)

Notez toutefois que pour Python versions supérieures à 3 (par exemple 3.2 ou 3.3), la deuxième option est préférable .

Pour plus d'informations sur l'option deux, je suggère ce lien sur formatage de chaîne à partir de la documentation Python .

Et pour plus d’informations sur l’option 1, ce lien sera suffisant et aura des informations sur les différents drapeaux .

Référence: Convertit un nombre à virgule flottante en une certaine précision, puis copie en chaîne

51
A.J.

TLDR;)

Le problème d'arrondi des entrées/sorties a été résolu définitivement par Python 2.7.0 et 3.1 .

Un nombre correctement arrondi peut être inversé de manière réversible:
str -> float() -> repr() -> float() ... ou Decimal -> float -> str -> Decimal
Un type décimal n'est plus nécessaire pour le stockage.


(Naturellement, il peut être nécessaire d'arrondir un résultat d'addition ou de soustraction de nombres arrondis pour éliminer les erreurs de dernier bit accumulées. Une arithmétique décimale explicite peut être encore utile, mais une conversion en chaîne par str() (c'est-à-dire avec arrondir à 12 chiffres valides) est suffisant si aucune précision extrême ou aucun nombre extrême d'opérations arithmétiques successives n'est requis.)

Test infini :

import random
from decimal import Decimal
for x in iter(random.random, None):           # Verify FOREVER that rounding is fixed :-)
    assert float(repr(x)) == x                # Reversible repr() conversion.
    assert float(Decimal(repr(x))) == x
    assert len(repr(round(x, 10))) <= 12      # Smart decimal places in repr() after round.
    if x >= 0.1:                              # Implicit rounding to 12 significant digits
        assert str(x) == repr(round(x, 12))   # by str() is good enough for small errors.
        y = 1000 * x                             # Decimal type is excessive for shopping
        assert str(y) == repr(round(y, 12 - 3))  # in a supermaket with Python 2.7+ :-)

Documentation

Voir le Notes de version Python 2.7 - Autres changements de langue le quatrième paragraphe:

Les conversions entre les nombres à virgule flottante et les chaînes sont maintenant correctement arrondies dans la plupart des cas. plates-formes. Ces conversions se produisent à différents endroits: str () sur des flottants et des nombres complexes; les constructeurs float et complex; mise en forme numérique; la sérialisation et la désérialisation des flottants et des nombres complexes à l'aide des modules marshal, pickle et json; analyse des littéraux float et imaginaires dans Python code; et conversion décimale à flottante.

En rapport avec cela, le repr () d'un nombre à virgule flottante x renvoie maintenant un résultat basé sur le plus court chaîne décimale garantie d’arrondir à x avec un arrondi correct (avec le mode arrondi arrondi-demi-à-pair). Auparavant, il donnait une chaîne en arrondissant x à 17 chiffres décimaux.

La question connexe


Plus d'informations: Le formatage de float avant Python 2.7 était similaire à l'actuel numpy.float64. Les deux types utilisent le même 64 bits IEEE 754 double précision avec mantisse 52 bits. Une grande différence est que np.float64.__repr__ est souvent formaté avec un nombre décimal excessif, de sorte qu'aucun bit ne peut être perdu, mais qu'aucun numéro IEEE 754 valide n'existe entre 13.949999999999999 et 13.950000000000001. Le résultat n'est pas Nice et la conversion repr(float(number_as_string)) n'est pas réversible avec numpy. D'autre part: float.__repr__ est formaté de manière à ce que chaque chiffre soit important; la séquence est sans lacunes et la conversion est réversible. Simplement: Si vous avez peut-être un nombre numpy.float64, convertissez-le en float normal afin d'être formaté pour les humains, pas pour les processeurs numériques, sinon rien n'est plus nécessaire avec Python 2.7+.

46
hynekcer

Vous pouvez modifier le format de sortie:

>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95
46
Greg Hewgill

Personne ici ne semble l'avoir encore mentionné, alors laissez-moi vous donner un exemple dans le format f-string/template-string de Python3.6, qui, à mon avis, est superbement ordonné:

>>> f'{a:.2f}'

Cela fonctionne bien aussi avec des exemples plus longs, avec des opérateurs et ne nécessitant pas de parens:

>>> print(f'Completed in {time.time() - start:.2f}s')
31
Matt Fletcher

Vous pouvez utiliser l'opérateur format pour arrondir la valeur à 2 décimales près en python:

print(format(14.4499923, '.2f')) // output is 14.45
29
Asad Manzoor

Dans Python 2.7:

a = 13.949999999999999
output = float("%0.2f"%a)
print output
27
Shashank Singh

Le tutoriel Python contient une annexe appelée Arithmétique en virgule flottante: problèmes et limitations. Lis le. Il explique ce qui se passe et pourquoi Python fait de son mieux. Il a même un exemple qui correspond au vôtre. Permettez-moi de citer un peu:

>>> 0.1
0.10000000000000001

vous pourriez être tenté d'utiliser la fonction round() pour le réduire au chiffre que vous attendez. Mais cela ne fait aucune différence:

>>> round(0.1, 1)
0.10000000000000001

Le problème est que la valeur à virgule flottante binaire stockée pour “0.1” était déjà la meilleure approximation binaire possible de 1/10. il reçoit.

Une autre conséquence est que, puisque 0.1 n'est pas exactement 1/10, la somme de dix valeurs de 0.1 peut ne pas donner exactement 1.0, soit:

>>> sum = 0.0
>>> for i in range(10):
...     sum += 0.1
...
>>> sum
0.99999999999999989

Une solution de rechange à vos problèmes consiste à utiliser le module decimal .

21
nosklo

Comme @Matt l’a souligné, Python 3.6 fournit des chaînes de caractères f , et ils peuvent également utiliser paramètres imbriqués:

value = 2.34558
precision = 2
width = 4

print(f'result: {value:{width}.{precision}f}')

qui affichera result: 2.35

12
toto_tico

Il fait exactement ce que vous lui avez dit de faire et fonctionne correctement. En savoir plus sur confusion en virgule flottante et peut-être essayer décimal objets.

12
HUAGHAGUAH

J'utilise cette technique pour corriger le nombre à virgule flottante dans les langages à typage dynamique tels que Python et JavaScript

# For example:
a = 70000
b = 0.14
c = a * b

print c # Prints 980.0000000002
# Try to fix
c = int(c * 10000)/100000
print c # Prints 980

Vous pouvez également utiliser Decimal comme suit:

from decimal import *
getcontext().prec = 6
Decimal(1) / Decimal(7)
# Results in 6 precision -> Decimal('0.142857')

getcontext().prec = 28
Decimal(1) / Decimal(7)
# Results in 28 precision -> Decimal('0.1428571428571428571428571429')
7
Siamand
orig_float = 232569 / 16000.0

14.5355625

short_float = float("{:.2f}".format(orig_float)) 

14.54

6
MikeL
from decimal import Decimal


def round_float(v, ndigits=2, rt_str=False):
    d = Decimal(v)
    v_str = ("{0:.%sf}" % ndigits).format(round(d, ndigits))
    if rt_str:
        return v_str
    return Decimal(v_str)

Résultats:

Python 3.6.1 (default, Dec 11 2018, 17:41:10)
>>> round_float(3.1415926)
Decimal('3.14')
>>> round_float(3.1445926)
Decimal('3.14')
>>> round_float(3.1455926)
Decimal('3.15')
>>> round_float(3.1455926, rt_str=True)
'3.15'
>>> str(round_float(3.1455926))
'3.15'
6
weaming

C'est simple comme 1,2,3:

  1. use decimal module pour l'arithmétique en virgule flottante décimale rapide correctement arrondie:

    d = décimal (10000000.0000009)

pour arrondir:

   d.quantize(Decimal('0.01'))

résultats avec Decimal('10000000.00')

  1. faire au dessus de DRY:
    def round_decimal(number, exponent='0.01'):
        decimal_value = Decimal(number)
        return decimal_value.quantize(Decimal(exponent))

OR

    def round_decimal(number, decimal_places=2):
        decimal_value = Decimal(number)
        return decimal_value.quantize(Decimal(10) ** -decimal_places)
  1. upvote cette réponse :)

PS: critique des autres: le formatage n’est pas arrondi.

4
Sławomir Lenart

Qu'en est-il une fonction lambda comme ceci:

arred = lambda x,n : x*(10**n)//1/(10**n)

De cette façon, vous pouvez simplement faire:

arred(3.141591657,2)

et obtenir

3.14
3

Utilisez une combinaison d'objet Decimal et de la méthode round ().

Python 3.7.3
>>> from decimal import Decimal
>>> d1 = Decimal (13.949999999999999) # define a Decimal
>>> d1 
Decimal('13.949999999999999289457264239899814128875732421875')
>>> d2 = round(d1, 2) # round to 2 decimals
>>> d2
Decimal('13.95')
2
Jonathan L

Pour arrondir un nombre à une résolution, la meilleure méthode est la suivante, qui peut fonctionner avec n'importe quelle résolution (0,01 pour deux décimales ou même d'autres étapes):

>>> import numpy as np
>>> value = 13.949999999999999
>>> resolution = 0.01
>>> newValue = int(np.round(value/resolution))*resolution
>>> print newValue
13.95

>>> resolution = 0.5
>>> newValue = int(np.round(value/resolution))*resolution
>>> print newValue
14.0
1
iblasi