Je veux a
être arrondi à 13,95 .
>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999
La round
fonction ne fonctionne pas comme je m'y attendais.
Je veux a
être arrondi à 13,95 .
>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999
La round
fonction ne fonctionne pas comme je m'y attendais.
Réponses:
Vous rencontrez l' ancien problème avec les nombres à virgule flottante que tous les nombres ne peuvent pas être représentés exactement. La ligne de commande vous montre simplement la forme flottante complète de la mémoire.
Avec une représentation en virgule flottante, votre version arrondie est le même nombre. Étant donné que les ordinateurs sont binaires, ils stockent des nombres à virgule flottante sous forme d'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 en double précision ont 53 bits (16 chiffres) de précision et les flottants réguliers ont 24 bits (8 chiffres) de précision. Le type à virgule flottante en 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("{:.2f}".format(a))
13.95
>>> print("{:.2f}".format(round(a, 2)))
13.95
>>> print("{:.15f}".format(round(a, 2)))
13.949999999999999
Si vous ne recherchez que deux décimales (pour afficher une valeur monétaire, par exemple), vous avez deux choix:
"%.2f" % round(a,2)
vous pouvez mettre non seulement dans printf, mais aussi dans des choses commestr()
float
) est juste l'approximation disponible la plus proche du nombre décimal (que vous connaissez en tant qu'être humain). Il n'existe aucune valeur binaire (représentable de manière finie) telle que 0,245. Elle n'existe tout simplement pas et mathématiquement ne peut pas exister. La valeur binaire qui est la plus proche de 0,245 est légèrement inférieure à 0,245, elle arrondit donc naturellement. De même, il n'existe pas de 0,225 en binaire, mais la valeur binaire qui est la plus proche de 0,225 est légèrement supérieure à 0,225, donc naturellement elle arrondit.
Decimal
, et c'était l'une des solutions présentées dans cette réponse. L'autre consistait à convertir vos quantités en nombres entiers et à utiliser l'arithmétique entière. Ces deux approches sont également apparues dans d'autres réponses et commentaires.
Il existe de nouvelles spécifications de format, String Mini-Language Specification :
Vous pouvez faire de même que:
"{:.2f}".format(13.949999999999999)
Remarque 1: ce qui précède renvoie une chaîne. Pour obtenir comme flotteur, enveloppez simplement avec float(...)
:
float("{:.2f}".format(13.949999999999999))
Remarque 2: l' emballage avec float()
ne change rien:
>>> x = 13.949999999999999999
>>> x
13.95
>>> g = float("{:.2f}".format(x))
>>> g
13.95
>>> x == g
True
>>> h = round(x, 2)
>>> h
13.95
>>> x == h
True
'{0:,.2f}'.format(1333.949999999)
imprimer '1,333.95'
.
float()
; float("{0:.2f}".format(13.9499999))
f"Result is {result:.2f}"
La fonction intégrée round()
fonctionne très bien en Python 2.7 ou version ultérieure.
Exemple:
>>> round(14.22222223, 2)
14.22
Consultez la documentation .
round(2.16, 1)
donnez 2.2
pourquoi python offre juste un truncate
func
>>> round(2.675, 2) 2.67
docs.python.org/2/tutorial/floatingpoint.html
Note The behavior of round() for floats can be surprising: for example, round(2.675, 2) gives 2.67 instead of the expected 2.68. This is not a bug: it’s a result of the fact that most decimal fractions can’t be represented exactly as a float.
Je pense que l'approche la plus simple consiste à utiliser la format()
fonction.
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.
Utilisation
print"{:.2f}".format(a)
au lieu de
print"{0:.2f}".format(a)
Parce que ce dernier peut entraîner des erreurs de sortie lors de la tentative de sortie de plusieurs variables (voir les commentaires).
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 requiert, vous devez utiliser arrondir. Si vous souhaitez simplement restreindre l'affichage à une certaine précision, n'utilisez même pas round et formatez-le simplement comme 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, mais peut-être le plus important, si vous voulez des mathématiques exactes, vous ne voulez pas du tout de flottants. L'exemple habituel consiste à gérer l'argent et à stocker les «cents» sous forme d'entier.
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
round
fonction en premier lieu. D'autre part, comme cette solution utilise toujours la virgule flottante, le problème d'origine de l'OP demeure, même pour la version "corrigée" de cette "solution".
round
fonction (qui a été utilisée dans la question).
round()
ne fonctionne pas comme l'OP mentionné.
Le problème d'arrondi des entrées / sorties a été définitivement résolu par Python 2.7.0 et 3.1 .
Un nombre correctement arrondi peut être converti de façon réversible d'avant en arrière:
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 accumulées du dernier bit. Une arithmétique décimale explicite peut être toujours pratique, mais une conversion en chaîne par str()
(c'est-à-dire en arrondissant à 12 chiffres valides) ) est généralement assez bonne 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+ :-)
Voir les notes de publication Python 2.7 - Autres changements de langue, 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 à de nombreux endroits différents: str () sur les flottants et les nombres complexes; le flotteur et les constructeurs complexes; formatage numérique; sérialisation et des flotteurs de-sérialisation et de nombres complexes en utilisant les
marshal
,pickle
et lesjson
modules; analyse des flottants et des littéraux imaginaires en code Python; et conversion décimale-à-flottante.En relation avec cela, la repr () d'un nombre à virgule flottante x retourne désormais un résultat basé sur la chaîne décimale la plus courte qui est garantie d'arrondir à x sous un arrondi correct (avec le mode d'arrondi demi-rond à pair). Auparavant, il donnait une chaîne basée sur l'arrondi de x à 17 chiffres décimaux.
Plus d'informations: Le formatage d' float
avant Python 2.7 était similaire à l'actuel numpy.float64
. Les deux types utilisent la même double précision IEEE 754 64 bits avec une mantisse 52 bits. Une grande différence est qu'il 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 numéro numpy.float64, convertissez-le en float normal afin d'être formaté pour les humains, pas pour les processeurs numériques, sinon rien de plus n'est nécessaire avec Python 2.7+.np.float64.__repr__
est fréquemment formaté avec un nombre décimal excessif afin qu'aucun bit ne puisse être perdu, mais aucun numéro IEEE 754 valide n'existe entre 13,94999999999999999 et 13,950000000000001. Le résultat n'est pas agréable et la conversion repr(float(number_as_string))
n'est pas réversible avec numpy. D'autre part:float.__repr__
float
(double précision) et normal round
, pas sur numpy.double et sa conversion en chaîne. L'arrondi Python simple ne peut vraiment pas être mieux fait que dans Python 2.7. La plupart des réponses ont été écrites avant la 2.7, mais elles sont obsolètes, même si elles étaient très bonnes à l'origine. C'est la raison de ma réponse.
1
, sauf lors d'un "dépassement progressif".
a*b
contre b*a
. Merci pour les liens - Nostalgie.
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 préférée .
Pour plus d'informations sur l'option deux, je suggère ce lien sur le formatage des chaînes de la documentation Python .
Et pour plus d'informations sur la première option, ce lien suffira et contient des informations sur les différents drapeaux .
Référence: convertir un nombre à virgule flottante avec une certaine précision, puis copier dans une chaîne
numvar=12.456
, alors "{:.2f}".format(numvar)
cède 12.46
mais "{:2i}".format(numvar)
donne une erreur et je m'attends 12
.
Vous pouvez modifier le format de sortie:
>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95
Personne ici ne semble l'avoir encore mentionné, alors permettez-moi de donner un exemple au format f-string / template-string de Python 3.6, qui je pense est magnifiquement soigné:
>>> f'{a:.2f}'
Cela fonctionne bien avec des exemples plus longs aussi, avec des opérateurs et sans besoin de parens:
>>> print(f'Completed in {time.time() - start:.2f}s')
Vous pouvez utiliser l' opérateur de format pour arrondir la valeur jusqu'à 2 décimales en python:
print(format(14.4499923, '.2f')) // output is 14.45
En Python 2.7:
a = 13.949999999999999
output = float("%0.2f"%a)
print output
output
a exactement la même valeur que a
, donc vous pourriez aussi bien avoir écrit print a
au lieu de print output
dans la dernière ligne.
13.95
. Mais il en va de même print a
pour cette valeur particulière de a
Python 2.7, il n'est donc pas vraiment clair quel était le point de l'étape de formatage.
a == output
le code que vous montrez? Cela True
me donne et je soupçonne que ça le fait aussi pour vous.
Le didacticiel Python comporte une annexe intitulée Arithmétique à virgule flottante: problèmes et limites . 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
round()
fonction pour la couper en un 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 possible1/10
, donc essayer de l'arrondir à nouveau 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 exactement1/10
, la somme de dix valeurs de0.1
peut ne pas donner exactement1.0
non plus:>>> 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 decimal
module.
Comme l'a souligné @Matt, Python 3.6 fournit des chaînes f , 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 result: 2.35
Il fait exactement ce que vous lui avez dit de faire et fonctionne correctement. En savoir plus sur la confusion en virgule flottante et peut-être essayer des objets décimaux à la place.
Utilisez une combinaison d'objet Decimal et de 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')
Pour fixer la virgule flottante dans les langages de type dynamique 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)
# Results in 6 precision -> Decimal('0.142857')
getcontext().prec = 28
Decimal(1) / Decimal(7)
# Results in 28 precision -> Decimal('0.1428571428571428571428571429')
getcontext().prec = 6
fonctionne pour la portée de la fonction ou pour tous les endroits?
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'
Qu'en est-il d'une fonction lambda comme celle-ci:
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
C'est simple comme 1,2,3:
utiliser décimal module pour une arithmétique décimale décimale à virgule flottante correctement arrondie:
d = décimal (10000000.0000009)
pour arrondir:
d.quantize(Decimal('0.01'))
sera résultats avec Decimal('10000000.00')
def round_decimal(number, exponent='0.01'):
decimal_value = Decimal(number)
return decimal_value.quantize(Decimal(exponent))
OU
def round_decimal(number, decimal_places=2):
decimal_value = Decimal(number)
return decimal_value.quantize(Decimal(10) ** -decimal_places)
PS: critique des autres: le formatage n'est pas arrondi.
Pour arrondir un nombre à une résolution, la meilleure façon 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
numpy.round
exactitude / précision. Il faut donc le définir comme entier avant multiplication avec résolution. J'ai mis à jour le code. Merci pour ça!
numpy.float64
résultat de np.round en float
ou simplement d'utiliser round(value, 2)
. Aucun numéro IEEE 754 valide n'existe entre le 13.94999999999999999 (= 1395 / 100.) et le 3.950000000000001 (= 1395 * .01). Pourquoi pensez-vous que votre méthode est la meilleure? La valeur d'origine 13.949999999999999289 (= valeur = round (valeur, 2)) est encore plus exacte que votre 13.950000000000001717 (imprimée par np.float96). Plus d'informations également pour numpy sont maintenant ajoutées à ma réponse que vous avez probablement downvoted par erreur. Il ne s'agissait pas de numpy à l'origine.
int
vous, vous pouvez également utiliser l' float
exemple @szeitlin. Merci pour votre commentaire supplémentaire. (Désolé mais je ne vous ai pas downvote)
La méthode que j'utilise est celle du découpage de chaîne. C'est relativement rapide et simple.
Tout d'abord, convertissez le flotteur en chaîne, puis choisissez la longueur que vous souhaitez qu'il soit.
float = str(float)[:5]
Dans la seule ligne ci-dessus, nous avons converti la valeur en chaîne, puis conservé la chaîne uniquement dans ses quatre premiers chiffres ou caractères (inclus).
J'espère que cela pourra aider!