round - python truncate float




Limitation des flotteurs à deux décimales (13)

tldr;)

Le problème d'arrondi à l'entrée / sortie a été résolu par Python 2.7.0 et 3.1 définitivement.

Test Infini:

import random
for x in iter(random.random, None):           # verify FOREVER that rounding is fixed :-)
    assert float(repr(x)) == x                # Reversible repr() conversion
    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 the supermaket with Python 2.7+ :-)

docs

Voir les notes de version Python 2.7 - Other Language Change le quatrième paragraphe:

Les conversions entre les nombres à virgule flottante et les chaînes sont désormais correctement arrondies sur la plupart des plates-formes. Ces conversions se produisent dans de nombreux endroits différents: str () sur les flottants et les nombres complexes; les constructeurs flottants et complexes; formatage numérique; sérialisation et désérialisation des flotteurs et des nombres complexes en utilisant les modules marshal, pickle et json; analyse de littéraux flottants et imaginaires en code Python; et conversion Decimal-to-float.

Relativement à ceci, le repr () d'un nombre à virgule flottante x renvoie maintenant un résultat basé sur la chaîne décimale la plus courte qui est garantie pour arrondir à x sous l'arrondi correct (avec le mode d'arrondi demi-rond-à-pair). Auparavant, il donnait une chaîne basée sur l'arrondissement de x à 17 chiffres décimaux.

Le problème connexe

EDIT - plus d'infos:: La mise en forme de float avant Python 2.7 était similaire à l'actuelle numpy.float64 . Les deux types utilisent la même double précision 64 bits IEEE 754 avec le mastic 52 bits. Une grande différence est que np.float64.__repr__ est formaté fréquemment avec un nombre décimal excessif de sorte qu'aucun bit ne peut être perdu, mais aucun numéro IEEE 754 valide n'existe entre 13.949999999999999 et 13.950000000000001, le résultat n'est pas sympa et la conversion repr(float(number_as_string)) n'est pas réversible. De l'autre côté: float.__repr__ est formaté de façon à ce que chaque chiffre soit important, la séquence est sans espaces 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 et non pour les processeurs numériques, sinon rien n'est plus nécessaire avec Python 2.7+.

Je veux a arrondi à 13.95 .

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

La fonction round ne fonctionne pas comme je l'espérais.


Avec python <3 (par exemple 2.6 ou 2.7), il y a 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)

Mais notez que pour les versions python supérieures à 3 (par exemple 3.2 ou 3.3), l'option deux est prefered

Pour plus d'informations sur l'option deux, je suggère ce lien sur la mise en forme de chaîne à partir des docs python .

Et pour plus d'informations sur l'option un, ce lien suffira et dispose d'informations sur les différents drapeaux.

Réfrence: Convertissez le nombre à virgule flottante en une certaine précision, puis copiez-le en chaîne


Comme l'a souligné @Matt, Python 3.6 fournit des f-strings , et ils peuvent également utiliser des paramètres imbriqués :

value = 2.34558
precision = 2
width = 4

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

qui affichera le result: 2.35


Essayez les codes ci-dessous:

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

Il y a de nouvelles spécifications de format, String Format Specification Mini-Language :

Vous pouvez faire la même chose que:

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

Notez que ce qui précède renvoie une chaîne. afin d'obtenir un flotteur, il suffit d'envelopper float(...)

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

Notez que 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

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 la forme d'une chaîne arrondie à deux décimales.


La plupart des nombres ne peuvent pas être représentés exactement dans les flottants. Si vous voulez arrondir le nombre parce que c'est ce que votre formule mathématique ou votre algorithme nécessite, alors vous voulez utiliser round. Si vous voulez juste restreindre l'affichage à une certaine précision, n'utilisez même pas round et formatez simplement cette chaîne. (Si vous voulez l'afficher avec une autre méthode d'arrondi, et il y a des tonnes, alors 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 des mathématiques exactes, vous ne voulez pas de flotteurs du tout. L'exemple habituel traite de l'argent et de stocker des «cents» en entier.


Le didacticiel Python comporte une annexe intitulée: Arithmétique des points flottants: 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 la rogner sur le seul chiffre que vous attendez. Mais cela ne fait aucune différence:

>>> round(0.1, 1)
0.10000000000000001

Le problème est que la valeur binaire à virgule flottante stockée pour “0.1” était déjà la meilleure approximation binaire possible à 1/10 , donc essayer de la contourner ne peut pas l'améliorer: elle était déjà aussi bonne que possible.

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 alternative et une solution à vos problèmes serait d'utiliser le module decimal .


Pour arrondir un nombre à une résolution, le meilleur moyen est le suivant, qui peut fonctionner avec n'importe quelle résolution (0,01 pour 2 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

Python 2.7,

J'espère que cela aidera

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

Vous rencontrez l'ancien problème avec des nombres à virgule flottante que tous les nombres ne peuvent pas être représentés. La ligne de commande ne fait que vous montrer le formulaire à virgule flottante depuis la mémoire. En virgule flottante, votre version arrondie est le même nombre. Puisque les ordinateurs sont binaires, ils stockent des nombres à virgule flottante sous la forme d'un nombre entier, puis le divisent par une puissance de deux, de sorte que 13.95 sera représenté de la même manière que 125650429603636838 / (2 ** 53). Les nombres double précision ont 53 bits (16 chiffres) de précision et les flotteurs normaux ont 24 bits (8 chiffres) de précision. Le point flottant dans python utilise une 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 disposez que de deux décimales en devise, vous avez deux choix meilleurs: utiliser des nombres entiers et stocker des valeurs en cents et non en dollars, puis diviser par 100 pour convertir en dollars. Ou utilisez un nombre à decimal fixe comme decimal


pour corriger le virgule flottante dans les langages dynamiques de type tels que Python et Javascript, j'utilise cette technique

# 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)
#result in 6 precision -> Decimal('0.142857')
getcontext().prec = 28
Decimal(1) / Decimal(7)
#result in 28 precision -> Decimal('0.1428571428571428571428571429')

orig_float = 232569 / 16000.0

14.5355625

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

14.54





precision