Pregunta

La documentación para el redondo() La función indica que le pasas un número y las posiciones más allá del decimal para redondear.Así es debería hacer esto:

n = 5.59
round(n, 1) # 5.6

Pero, en realidad, la vieja rareza del punto flotante aparece y obtienes:

5.5999999999999996

Para fines de la interfaz de usuario, necesito mostrar 5.6.Busqué en Internet y encontré algunos documentación que esto depende de mi implementación de Python.Desafortunadamente, esto ocurre tanto en mi máquina de desarrollo de Windows como en cada servidor Linux que he probado. Ver aquí también.

Aparte de crear mi propia biblioteca circular, ¿hay alguna forma de evitarlo?

¿Fue útil?

Solución

No puedo evitar la forma en que se almacena, pero al menos el formateo funciona correctamente:

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

Otros consejos

El formateo funciona correctamente incluso sin tener que redondear:

"%.1f" % n

Si usa el módulo Decimal, puede aproximar sin el uso de la función 'redondear'.Esto es lo que he estado usando para redondear, especialmente al escribir aplicaciones monetarias:

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

Esto devolverá un número decimal que es 16,20.

round(5.59, 1) está funcionando bien.El problema es que 5.6 no se puede representar exactamente en coma flotante binaria.

>>> 5.6
5.5999999999999996
>>> 

Como dice Vinko, puede utilizar el formato de cadena para redondear la visualización.

Python tiene un módulo para aritmética decimal si necesitas eso.

Obtendrás '5.6' si lo haces str(round(n, 1)) en lugar de solo round(n, 1).

Puede cambiar el tipo de datos a un número entero:

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

Y luego muestre el número insertando el separador decimal de la configuración regional.

Sin embargo, la respuesta de jimmy es mejor.

Las matemáticas de coma flotante son vulnerables a imprecisiones de precisión leves, pero molestas.Si puede trabajar con números enteros o con punto fijo, tendrá garantizada la precisión.

Échale un vistazo al módulo decimal

Decimal "se basa en un modelo de punto flotante que fue diseñado con las personas en mente, y necesariamente tiene un principio rector de primordial: las computadoras deben proporcionar una aritmética que funcione de la misma manera que la aritmética que las personas aprenden en la escuela". - Extracto de la especificación aritmética decimal.

y

Los números decimales se pueden representar exactamente.En contraste, números como 1.1 y 2.2 no tienen representaciones exactas en el punto flotante binario.Los usuarios finales generalmente no esperarían que 1.1 + 2.2 se muestre como 3.30000000000000033 como lo hace con el punto flotante binario.

Decimal proporciona el tipo de operaciones que facilitan la escritura de aplicaciones que requieren operaciones de punto flotante y también Es necesario presentar esos resultados en un formato legible por humanos, por ejemplo, contabilidad.

Es un gran problema en verdad.Pruebe este código:

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

Muestra 4,85.Entonces haces:

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

y muestra 4.8.¿Haces cálculos a mano? La respuesta exacta es 4,85, pero si lo intentas:

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

puedes ver la verdad:el punto flotante se almacena como la suma finita más cercana de fracciones cuyos denominadores son potencias de dos.

Puedes usar el operador de formato de cadena. %, similar a sprintf.

mystring = "%.2f" % 5.5999

imprimirf el tonto.

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

Funciona perfecto

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

Estoy haciendo:

int(round( x , 0))

En este caso, primero redondeamos correctamente a nivel de unidad y luego convertimos a entero para evitar imprimir un valor flotante.

entonces

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

Creo que esta respuesta funciona mejor que formatear la cadena y también tiene más sentido para mí usar la función redonda.

Código:

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'

Producción:

5.6
5.7

Aquí es donde veo que la ronda falla.¿Qué pasaría si quisieras redondear estos 2 números a un decimal?23.45 23.55 Mi educación fue que al redondearlos deberías obtener:23.4 23.6 La "regla" es que debe redondear si el número anterior era impar, no redondeado si el número anterior era uniforme.La función redonda en Python simplemente trunca el 5.

El problema sólo surge cuando el último dígito es 5.P.ej.0,045 se almacena internamente como 0,044999999999999...Simplemente podrías incrementar el último dígito a 6 y redondear.Esto le dará los resultados deseados.

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

Qué pasa:

round(n,1)+epsilon
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top