Voglio a
essere arrotondato a 13.95 .
>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999
La round
funzione non funziona nel modo previsto.
Voglio a
essere arrotondato a 13.95 .
>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999
La round
funzione non funziona nel modo previsto.
Risposte:
Stai incontrando il vecchio problema con i numeri in virgola mobile che non tutti i numeri possono essere rappresentati esattamente. La riga di comando mostra solo il modulo in virgola mobile completo dalla memoria.
Con la rappresentazione in virgola mobile, la versione arrotondata ha lo stesso numero. Poiché i computer sono binari, memorizzano i numeri in virgola mobile come numeri interi e quindi li dividono per una potenza di due, quindi 13,95 sarà rappresentato in modo simile a 125650429603636838 / (2 ** 53).
I numeri a doppia precisione hanno 53 bit (16 cifre) di precisione e i float regolari hanno 24 bit (8 cifre) di precisione. Il tipo a virgola mobile in Python utilizza la doppia precisione per memorizzare i valori.
Per esempio,
>>> 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
Se stai cercando solo due cifre decimali (per visualizzare un valore di valuta, ad esempio), hai un paio di scelte migliori:
"%.2f" % round(a,2)
è possibile inserire non solo in printf, ma anche in cose comestr()
float
) è solo l'approssimazione disponibile più vicina al numero decimale (che conosci come essere umano). Non esiste un valore binario (finemente rappresentabile) come 0,245. Semplicemente non esiste e matematicamente non può esistere. Il valore binario che è il più vicino a 0,245 è leggermente inferiore a 0,245, quindi naturalmente viene arrotondato per difetto. Allo stesso modo, non esiste nulla come 0,225 in binario, ma il valore binario che è il più vicino a 0,225 è leggermente maggiore di 0,225, quindi naturalmente arrotonda per eccesso.
Decimal
, e quella era una delle soluzioni presentate in questa risposta. L'altro era convertire le quantità in numeri interi e usare l'aritmetica dei numeri interi. Entrambi questi approcci sono comparsi anche in altre risposte e commenti.
Esistono nuove specifiche di formato, Mini-lingua di specifica del formato di stringa :
Puoi fare lo stesso di:
"{:.2f}".format(13.949999999999999)
Nota 1: quanto sopra restituisce una stringa. Per ottenere il galleggiante, basta avvolgere con float(...)
:
float("{:.2f}".format(13.949999999999999))
Nota 2: il wrapping con float()
non cambia nulla:
>>> 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)
stampare '1,333.95'
.
float()
; float("{0:.2f}".format(13.9499999))
f"Result is {result:.2f}"
Il built-in round()
funziona perfettamente in Python 2.7 o versioni successive.
Esempio:
>>> round(14.22222223, 2)
14.22
Consulta la documentazione .
round(2.16, 1)
dare 2.2
perché pitone solo offrono una truncate
fun
>>> 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.
Sento che l'approccio più semplice è usare la format()
funzione.
Per esempio:
a = 13.949999999999999
format(a, '.2f')
13.95
Questo produce un numero float come una stringa arrotondata a due punti decimali.
Uso
print"{:.2f}".format(a)
invece di
print"{0:.2f}".format(a)
Perché quest'ultimo può causare errori di output quando si tenta di generare più variabili (vedere i commenti).
La maggior parte dei numeri non può essere rappresentata esattamente in float. Se vuoi arrotondare il numero perché è quello che richiede la tua formula matematica o algoritmo, allora vuoi usare round. Se vuoi solo limitare il display a una certa precisione, non usare nemmeno round e formattalo semplicemente come quella stringa. (Se vuoi visualizzarlo con un metodo di arrotondamento alternativo e ci sono tonnellate, allora devi mescolare i due approcci.)
>>> "%.2f" % 3.14159
'3.14'
>>> "%.2f" % 13.9499999
'13.95'
E infine, anche se forse più importante, se vuoi la matematica esatta non vuoi affatto galleggiare. L'esempio usuale riguarda il denaro e l'archiviazione dei "centesimi" come numeri interi.
Prova il codice qui sotto:
>>> a = 0.99334
>>> a = int((a * 100) + 0.5) / 100.0 # Adding 0.5 rounds it up
>>> print a
0.99
round
funzione in primo luogo. D'altra parte, poiché questa soluzione utilizza ancora in virgola mobile, il problema originale dell'OP rimane, anche per la versione "corretta" di questa "soluzione".
round
funzione (che è stata utilizzata nella domanda).
round()
non funziona come indicato nell'OP.
Il problema di arrotondamento di input / output è stato risolto definitivamente da Python 2.7.0 e 3.1 .
Un numero arrotondato correttamente può essere convertito in modo reversibile avanti e indietro:
str -> float() -> repr() -> float() ...
oppure Decimal -> float -> str -> Decimal
Un tipo decimale non è più necessario per la memorizzazione.
(Naturalmente, può essere necessario arrotondare un risultato di addizione o sottrazione di numeri arrotondati per eliminare gli errori dell'ultimo bit accumulato. Un'aritmetica decimale esplicita può essere ancora utile, ma una conversione in stringa di str()
(ovvero arrotondando a 12 cifre valide ) è abbastanza buono di solito se non è richiesta una precisione estrema o un numero estremo di operazioni aritmetiche successive.)
Test infinito :
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+ :-)
Vedi le note di rilascio Python 2.7 - Altre modifiche alla lingua il quarto paragrafo:
Le conversioni tra numeri in virgola mobile e stringhe sono ora arrotondate correttamente sulla maggior parte delle piattaforme. Queste conversioni si verificano in molti luoghi diversi: str () su float e numeri complessi; il galleggiante e costruttori complessi; formattazione numerica; serializzare e deserializzare float e numeri complessi usando il
marshal
,pickle
ejson
moduli; analisi di float e letterali immaginari in codice Python; e conversione da decimale a virgola mobile.A questo proposito, il repr () di un numero a virgola mobile x ora restituisce un risultato basato sulla stringa decimale più corta che è garantita per arrotondare a x con arrotondamento corretto (con la modalità di arrotondamento da metà arrotondata a uniforme). In precedenza forniva una stringa basata sull'arrotondamento da x a 17 cifre decimali.
Ulteriori informazioni: La formattazione di float
Python 2.7 precedente era simile all'attuale numpy.float64
. Entrambi i tipi usano la stessa doppia precisione IEEE 754 a 64 bit con mantissa a 52 bit. Una grande differenza è che np.float64.__repr__
viene formattato frequentemente con un numero decimale eccessivo in modo da non perdere alcun bit, ma non esiste un numero IEEE 754 valido compreso tra 13.949999999999999 e 13.95000000000000001. Il risultato non è buono e la conversione repr(float(number_as_string))
non è reversibile con numpy. D'altro canto:float.__repr__
è formattato in modo che ogni cifra sia importante; la sequenza è senza lacune e la conversione è reversibile. Semplicemente: se hai forse un numero numpy.float64, convertilo in un normale float per essere formattato per gli umani, non per processori numerici, altrimenti con Python 2.7+ non è necessario altro.
float
(doppia precisione) e normale round
, non numpy.double e la sua conversione in stringa. L'arrotondamento di Python semplice non può davvero essere fatto meglio di Python 2.7. La maggior parte delle risposte è stata scritta prima della 2.7, ma sono obsolete, sebbene in origine fossero molto buone. Questa è la ragione della mia risposta.
1
, tranne durante il "underflow graduale".
a*b
contro b*a
. Grazie per i link - Nostalgia.
Con Python <3 (ad es. 2.6 o 2.7), ci sono due modi per farlo.
# Option one
older_method_string = "%.9f" % numvar
# Option two (note ':' before the '.9f')
newer_method_string = "{:.9f}".format(numvar)
Tuttavia, per le versioni Python precedenti alla 3 (ad es. 3.2 o 3.3), si preferisce l' opzione due .
Per ulteriori informazioni sull'opzione due, suggerisco questo link sulla formattazione delle stringhe dalla documentazione di Python .
E per ulteriori informazioni sull'opzione 1, questo collegamento è sufficiente e contiene informazioni sui vari flag .
Riferimento: converte il numero in virgola mobile in una certa precisione, quindi copia in stringa
numvar=12.456
, allora "{:.2f}".format(numvar)
cede 12.46
ma "{:2i}".format(numvar)
dà un errore e mi aspetto 12
.
È possibile modificare il formato di output:
>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95
Nessuno qui sembra averlo ancora menzionato, quindi lasciatemi fare un esempio nel formato f-string / template-string di Python 3.6, che penso sia meravigliosamente pulito:
>>> f'{a:.2f}'
Funziona bene anche con esempi più lunghi, con operatori e senza bisogno di parentesi:
>>> print(f'Completed in {time.time() - start:.2f}s')
È possibile utilizzare l' operatore formato per arrotondare il valore fino a 2 posizioni decimali in Python:
print(format(14.4499923, '.2f')) // output is 14.45
In Python 2.7:
a = 13.949999999999999
output = float("%0.2f"%a)
print output
output
ha lo stesso identico valore di a
, quindi potresti anche aver scritto print a
invece che print output
nell'ultima riga.
13.95
. Ma lo stesso vale print a
, per questo particolare valore di a
, in Python 2.7, quindi non è davvero chiaro quale fosse il punto del passaggio di formattazione.
a == output
il codice che mostri? Dà True
per me, e sospetto che lo faccia anche per te.
Il tutorial di Python ha un'appendice chiamata Aritmetica in virgola mobile: problemi e limitazioni . Leggilo. Spiega cosa sta succedendo e perché Python sta facendo del suo meglio. Ha anche un esempio che corrisponde al tuo. Vorrei citare un po ':
>>> 0.1 0.10000000000000001
potresti essere tentato di utilizzare la
round()
funzione per ridurla alla singola cifra che ti aspetti. Ma questo non fa differenza:>>> round(0.1, 1) 0.10000000000000001
Il problema è che il valore binario a virgola mobile memorizzato per
“0.1”
era già la migliore approssimazione possibile a1/10
, quindi provare a arrotondarlo di nuovo non può renderlo migliore: era già buono come può.Un'altra conseguenza è che poiché
0.1
non è esattamente1/10
, sommando dieci valori di0.1
potrebbe non produrre esattamente1.0
, neanche:>>> sum = 0.0 >>> for i in range(10): ... sum += 0.1 ... >>> sum 0.99999999999999989
Un'alternativa e una soluzione ai tuoi problemi sarebbe usare il decimal
modulo.
Come sottolineato da @Matt, Python 3.6 fornisce stringhe f e possono anche usare parametri nidificati :
value = 2.34558
precision = 2
width = 4
print(f'result: {value:{width}.{precision}f}')
che verrà visualizzato result: 2.35
Sta facendo esattamente quello che gli hai detto di fare e funziona correttamente. Leggi di più sulla confusione in virgola mobile e magari prova invece gli oggetti decimali .
Utilizzare la combinazione di oggetto decimale e metodo 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')
Per fissare il virgola mobile in linguaggi di tipo dinamico come Python e JavaScript, utilizzo questa tecnica
# 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
Puoi anche usare Decimale come segue:
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
funziona solo nell'ambito della funzione o in tutti i luoghi?
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)
risultati:
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'
Che dire di una funzione lambda come questa:
arred = lambda x,n : x*(10**n)//1/(10**n)
In questo modo potresti semplicemente fare:
arred(3.141591657,2)
e prendi
3.14
È semplice come 1,2,3:
usa il decimale modulo per un'aritmetica decimale a virgola mobile rapidamente arrotondata correttamente:
d = decimale (10000000.0000009)
per arrotondare:
d.quantize(Decimal('0.01'))
risulterà con Decimal('10000000.00')
def round_decimal(number, exponent='0.01'):
decimal_value = Decimal(number)
return decimal_value.quantize(Decimal(exponent))
O
def round_decimal(number, decimal_places=2):
decimal_value = Decimal(number)
return decimal_value.quantize(Decimal(10) ** -decimal_places)
PS: critica degli altri: la formattazione non è arrotondata.
Per arrotondare un numero a una risoluzione, il modo migliore è il seguente, che può funzionare con qualsiasi risoluzione (0,01 per due decimali o anche altri passaggi):
>>> 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
dall'accuratezza / precisione. Quindi richiede di definirlo come int prima della moltiplicazione con risoluzione. Ho aggiornato il codice. Grazie per questo!
numpy.float64
risultato di np.round in float
o semplicemente usarlo round(value, 2)
. Non esiste un numero IEEE 754 valido compreso tra 13.949999999999999 (= 1395 / 100.) e 3.950000000000001 (= 1395 * .01). Perché pensi che il tuo metodo sia il migliore? Il valore originale 13.949999999999999289 (= valore = rotondo (valore, 2)) è ancora più esatto del tuo 13.9500000000000000178 (stampato da np.float96). Ulteriori informazioni anche per numpy sono ora aggiunte alla mia risposta che probabilmente hai effettuato il downvoting per errore. All'inizio non si trattava di intorpidimento.
int
tuo puoi usare anche float
per l'esempio @szeitlin. Grazie per il tuo commento extra. (Scusate ma non vi ho
Il metodo che uso è quello del taglio delle stringhe. È relativamente veloce e semplice.
Innanzitutto, converti il float in una stringa, quindi scegli la lunghezza che desideri che sia.
float = str(float)[:5]
Nella singola riga sopra, abbiamo convertito il valore in una stringa, quindi abbiamo mantenuto la stringa solo nelle sue prime quattro cifre o caratteri (inclusi).
Spero che aiuti!