Domanda

La documentazione per il girare() La funzione afferma che gli passi un numero e che le posizioni oltre il decimale vengono arrotondate.Così Dovrebbe Fai questo:

n = 5.59
round(n, 1) # 5.6

Ma, in realtà, la buona vecchia stranezza della virgola mobile si insinua e ottieni:

5.5999999999999996

Ai fini dell'interfaccia utente, devo visualizzare 5.6.Ho fatto un giro su Internet e ne ho trovati alcuni documentazione che questo dipende dalla mia implementazione di Python.Sfortunatamente, questo si verifica sia sul mio computer di sviluppo Windows che su ogni server Linux che ho provato. Vedi anche qui.

A parte creare la mia libreria rotonda, c'è un modo per aggirare questo problema?

È stato utile?

Soluzione

Non posso aiutare il modo in cui è archiviato, ma almeno la formattazione funziona correttamente:

'%.1f' % round(n, 1) # Gives you '5.6'

Altri suggerimenti

La formattazione funziona correttamente anche senza dover arrotondare:

"%.1f" % n

Se usi il modulo Decimal puoi approssimare senza usare la funzione 'round'.Ecco cosa ho usato per arrotondare soprattutto quando scrivo domande monetarie:

Decimal(str(16.2)).quantize(Decimal('.01'), rounding=ROUND_UP)

Ciò restituirà un numero decimale che è 16.20.

round(5.59, 1) funziona bene.Il problema è che 5.6 non può essere rappresentato esattamente in virgola mobile binaria.

>>> 5.6
5.5999999999999996
>>> 

Come dice Vinko, puoi utilizzare la formattazione delle stringhe per eseguire l'arrotondamento per la visualizzazione.

Python ha un modulo per l'aritmetica decimale se ne hai bisogno.

Se lo fai, ottieni "5.6". str(round(n, 1)) invece che solo round(n, 1).

Puoi cambiare il tipo di dati in un numero intero:

>>> n = 5.59
>>> int(n * 10) / 10.0
5.5
>>> int(n * 10 + 0.5)
56

Quindi visualizza il numero inserendo il separatore decimale della locale.

Tuttavia, La risposta di Jimmy è meglio.

La matematica in virgola mobile è vulnerabile a lievi, ma fastidiose, imprecisioni di precisione.Se puoi lavorare con numeri interi o virgole fisse, la precisione sarà garantita.

Dai un'occhiata a Modulo decimale

Decimal "si basa su un modello a punta mobile progettata pensando alle persone e ha necessariamente un principio guida fondamentale: i computer devono fornire un'aritmetica che funzioni allo stesso modo dell'aritmetica che le persone imparano a scuola". - estratto dalle specifiche aritmetiche decimali.

E

I numeri decimali possono essere rappresentati esattamente.Al contrario, numeri come 1.1 e 2.2 non hanno rappresentazioni esatte nel punto mobile binario.Gli utenti finali in genere non si aspetterebbero che 1.1 + 2.2 vengano visualizzati come 3.3000000000000003 come con il punto mobile binario.

Decimal fornisce il tipo di operazioni che semplificano la scrittura di app che richiedono operazioni in virgola mobile e Anche necessità di presentare tali risultati in un formato leggibile dall'uomo, ad esempio contabile.

È davvero un grosso problema.Prova questo codice:

print "%.2f" % (round((2*4.4+3*5.6+3*4.4)/8,2),)

Visualizza 4,85.Quindi fai:

print "Media = %.1f" % (round((2*4.4+3*5.6+3*4.4)/8,1),)

e mostra 4.8.Fai i calcoli a mano la risposta esatta è 4,85, ma se provi:

print "Media = %.20f" % (round((2*4.4+3*5.6+3*4.4)/8,20),)

puoi vedere la verità:il punto mobile viene memorizzato come la somma finita più vicina delle frazioni i cui denominatori sono potenze di due.

È possibile utilizzare l'operatore del formato stringa %, simile a sprintf.

mystring = "%.2f" % 5.5999

printf il pollone.

print '%.1f' % 5.59  # returns 5.6

Funziona perfettamente

format(5.59, '.1f') # to display
float(format(5.59, '.1f')) #to round

Sto facendo:

int(round( x , 0))

In questo caso, prima arrotondiamo correttamente a livello di unità, quindi convertiamo in numero intero per evitare di stampare un valore in virgola mobile.

COSÌ

>>> int(round(5.59,0))
6

Penso che questa risposta funzioni meglio della formattazione della stringa e per me ha anche più senso utilizzare la funzione round.

Codice:

x1 = 5.63
x2 = 5.65
print(float('%.2f' % round(x1,1)))  # gives you '5.6'
print(float('%.2f' % round(x2,1)))  # gives you '5.7'

Produzione:

5.6
5.7

È qui che vedo il fallimento del round.E se volessi arrotondare questi 2 numeri a una cifra decimale?23.45 23.55 La mia educazione era che dallo arrotondare questi dovresti ottenere:23.4 23.6 La "regola" è che dovresti arrotondare se il numero precedente era dispari, non arrotondata se il numero precedente fosse pari.La funzione round in Python tronca semplicemente 5.

Il problema è solo quando l'ultima cifra è 5.Per esempio.0,045 è memorizzato internamente come 0,044999999999999...Potresti semplicemente incrementare l'ultima cifra a 6 e arrotondare.Questo ti darà i risultati desiderati.

import re


def custom_round(num, precision=0):
    # Get the type of given number
    type_num = type(num)
    # If the given type is not a valid number type, raise TypeError
    if type_num not in [int, float, Decimal]:
        raise TypeError("type {} doesn't define __round__ method".format(type_num.__name__))
    # If passed number is int, there is no rounding off.
    if type_num == int:
        return num
    # Convert number to string.
    str_num = str(num).lower()
    # We will remove negative context from the number and add it back in the end
    negative_number = False
    if num < 0:
        negative_number = True
        str_num = str_num[1:]
    # If number is in format 1e-12 or 2e+13, we have to convert it to
    # to a string in standard decimal notation.
    if 'e-' in str_num:
        # For 1.23e-7, e_power = 7
        e_power = int(re.findall('e-[0-9]+', str_num)[0][2:])
        # For 1.23e-7, number = 123
        number = ''.join(str_num.split('e-')[0].split('.'))
        zeros = ''
        # Number of zeros = e_power - 1 = 6
        for i in range(e_power - 1):
            zeros = zeros + '0'
        # Scientific notation 1.23e-7 in regular decimal = 0.000000123
        str_num = '0.' + zeros + number
    if 'e+' in str_num:
        # For 1.23e+7, e_power = 7
        e_power = int(re.findall('e\+[0-9]+', str_num)[0][2:])
        # For 1.23e+7, number_characteristic = 1
        # characteristic is number left of decimal point.
        number_characteristic = str_num.split('e+')[0].split('.')[0]
        # For 1.23e+7, number_mantissa = 23
        # mantissa is number right of decimal point.
        number_mantissa = str_num.split('e+')[0].split('.')[1]
        # For 1.23e+7, number = 123
        number = number_characteristic + number_mantissa
        zeros = ''
        # Eg: for this condition = 1.23e+7
        if e_power >= len(number_mantissa):
            # Number of zeros = e_power - mantissa length = 5
            for i in range(e_power - len(number_mantissa)):
                zeros = zeros + '0'
            # Scientific notation 1.23e+7 in regular decimal = 12300000.0
            str_num = number + zeros + '.0'
        # Eg: for this condition = 1.23e+1
        if e_power < len(number_mantissa):
            # In this case, we only need to shift the decimal e_power digits to the right
            # So we just copy the digits from mantissa to characteristic and then remove
            # them from mantissa.
            for i in range(e_power):
                number_characteristic = number_characteristic + number_mantissa[i]
            number_mantissa = number_mantissa[i:]
            # Scientific notation 1.23e+1 in regular decimal = 12.3
            str_num = number_characteristic + '.' + number_mantissa
    # characteristic is number left of decimal point.
    characteristic_part = str_num.split('.')[0]
    # mantissa is number right of decimal point.
    mantissa_part = str_num.split('.')[1]
    # If number is supposed to be rounded to whole number,
    # check first decimal digit. If more than 5, return
    # characteristic + 1 else return characteristic
    if precision == 0:
        if mantissa_part and int(mantissa_part[0]) >= 5:
            return type_num(int(characteristic_part) + 1)
        return type_num(characteristic_part)
    # Get the precision of the given number.
    num_precision = len(mantissa_part)
    # Rounding off is done only if number precision is
    # greater than requested precision
    if num_precision <= precision:
        return num
    # Replace the last '5' with 6 so that rounding off returns desired results
    if str_num[-1] == '5':
        str_num = re.sub('5$', '6', str_num)
    result = round(type_num(str_num), precision)
    # If the number was negative, add negative context back
    if negative_number:
        result = result * -1
    return result

Che dire:

round(n,1)+epsilon
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top