plots - python plot library




Limitando i float a due decimali (13)

TLDR;)

Il problema di arrotondamento a input / output è stato risolto definitivamente da Python 2.7.0 e 3.1 .

Test infinito:

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+ :-)

Documentazione

Vedi le note di rilascio Python 2.7 - Altre modifiche linguistiche il quarto paragrafo:

Le conversioni tra numeri in virgola mobile e stringhe ora sono correttamente arrotondate sulla maggior parte delle piattaforme. Queste conversioni si verificano in molti posti diversi: str () su float e numeri complessi; il galleggiante e costruttori complessi; formattazione numerica; serializzare e de-serializzare float e numeri complessi usando i moduli marshal , pickle e json ; analisi di letterali float e immaginari in codice Python; e conversione da decimale a virgola mobile.

In relazione a ciò, il repr () di un numero in virgola mobile x restituisce ora un risultato basato sulla stringa decimale più corta che è garantita per arrotondare a x sotto arrotondamento corretto (con arrotondamento da metà a pari). In precedenza forniva una stringa basata sull'arrotondamento da x a 17 cifre decimali.

Il problema correlato

Ulteriori informazioni:: La formattazione di float prima di Python 2.7 era simile all'attuale numpy.float64 . Entrambi i tipi utilizzano la stessa precisione a 64 bit IEEE 754 con mantissa a 52 bit. Una grande differenza è che np.float64.__repr__ è formattato frequentemente con un numero decimale eccessivo in modo che nessun bit possa essere perso, ma non esiste un numero IEEE 754 valido tra 13.949999999999999 e 13.950000000000001. Il risultato non è carino e la conversione repr(float(number_as_string)) non è reversibile. D'altra parte: float.__repr__ è formattato in modo che ogni cifra sia importante; la sequenza è senza spazi e la conversione è reversibile. Semplicemente: se si ha un numero di numpy.float64, convertirlo in normale float per poter essere formattato per gli umani, non per i processori numerici, altrimenti non è necessario altro con Python 2.7+.

Voglio essere arrotondato a 13,95 .

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

La funzione round non funziona come mi aspettavo.


È possibile modificare il formato di output:

>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95

Come ha sottolineato @Matt, Python 3.6 fornisce stringhe di tipo f , e possono anche utilizzare parametri nidificati :

value = 2.34558
precision = 2
width = 4

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

che visualizzerà il result: 2.35


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)

Si noti che per le versioni di Python superiori a 3 (ad esempio, 3.2 o 3.3), l'opzione due è preferred .

Per maggiori informazioni sull'opzione 2, suggerisco questo collegamento sulla formattazione delle stringhe dalla documentazione di Python .

E per maggiori informazioni sull'opzione 1, questo link sarà sufficiente e ha informazioni sulle varie bandiere .

Riferimento: convertire il numero in virgola mobile in una certa precisione, quindi copiare in stringa


Il metodo che utilizzo è quello di slicing delle stringhe. È relativamente veloce e semplice.

Innanzitutto, converti il ​​float in una stringa, scegli la lunghezza che vorresti che fosse.

float = str(float)[:5]

Nella riga singola sopra, abbiamo convertito il valore in una stringa, quindi abbiamo mantenuto la stringa solo sulle sue prime quattro cifre o caratteri (inclusi).

Spero che sia d'aiuto!


Il tutorial Python ha un'appendice chiamata Floating Point Arithmetic: Issues and Limitations . Leggilo. Spiega cosa sta succedendo e perché Python sta facendo del suo meglio. Ha anche un esempio che corrisponde al tuo. Lasciatemi citare un po ':

>>> 0.1
0.10000000000000001

potresti essere tentato di utilizzare la funzione round() per riportarla alla singola cifra che ti aspetti. Ma non fa differenza:

>>> round(0.1, 1)
0.10000000000000001

Il problema è che il valore in virgola mobile binario memorizzato per “0.1” era già la migliore approssimazione binaria possibile a 1/10 , quindi provare a arrotondarlo di nuovo non può renderlo migliore: era già buono come si ottiene.

Un'altra conseguenza è che poiché 0.1 non è esattamente 1/10 , sommare dieci valori di 0.1 potrebbe non produrre esattamente 1.0 , o:

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

Un'alternativa e una soluzione ai tuoi problemi potrebbero utilizzare il modulo decimal .


Io uso questa tecnica per correggere il virgola mobile nei linguaggi di tipo dinamico come Python e 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

Puoi anche usare Decimal 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')

La maggior parte dei numeri non può essere rappresentata esattamente nei float. Se vuoi arrotondare il numero perché è quello che la tua formula o algoritmo matematico richiede, allora vuoi usare round. Se si desidera limitare il display a una certa precisione, non utilizzare nemmeno il round e formattarlo come tale 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 la cosa più importante, se vuoi la matematica esatta, allora non vuoi affatto i float. Il solito esempio riguarda il denaro e i "centesimi" come numeri interi.


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

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


Stai incontrando il vecchio problema con i numeri in virgola mobile che tutti i numeri non possono essere rappresentati. La riga di comando ti mostra solo il modulo a virgola mobile completo dalla memoria.

In virgola mobile la versione arrotondata è 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, pertanto 13.95 verrà 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 punto 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("{0:.2f}".format(a))
  13.95
  >>> print("{0:.2f}".format(round(a,2)))
  13.95
  >>> print("{0:.15f}".format(round(a,2)))
  13.949999999999999

Se si seguono solo due cifre decimali come in valuta, si hanno un paio di scelte migliori: 1) Utilizzare numeri interi e memorizzare valori in centesimi, non in dollari e quindi dividere per 100 per convertire in dollari. 2) O utilizzare un numero di punto fisso come decimal .


orig_float = 232569 / 16000.0

14.5355625

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

14.54







precision