[pyar] Valores incorrectos

Pablo Ziliani pablo en kultroom.com
Vie Oct 15 19:13:56 ART 2010


Diego E. Ahumada wrote:
>
> 2010/10/15 Cristian Segura <ska.python en gmail.com 
> <mailto:ska.python en gmail.com>>
>
>     Buenas chicos, mi primer duda a la lista :P
>
>     Estaba resolviendo un ejercicio, y me surgió un problema. El
>     ejercicio en cuestión es el siguiente:
>
>     "Dada una cantidad de dinero, indicar como repartir el vuelto de
>     manera que se utilice la menor cantidad de monedas"
>
>     El código que tengo es el siguiente:
>
>     b = (100, 50, 20, 10, 5, 2, 1, .5, .25, .1, .05)
>
>     v = float(raw_input("Ingrese vuelto: "))
>     i = 0
>     j = 0
>     l = len(b)
>
>     while i != l:
>         while v - b[i] >= 0:
>             v -= b[i]
>             j += 1
>         if j != 0:
>             print j, " billetes/monedas de ", b[i]
>             print "El valor restante es: ", v    # Esta unicamente
>     para comprobar los resultados
>         j = 0
>         i += 1
>
>     La salida del script utilizando como valor 1807.35 es: 
>
>     18  billetes/monedas de  100
>     El valor restante es:  7.35
>     1  billetes/monedas de  5
>     El valor restante es:  2.35
>     1  billetes/monedas de  2
>     El valor restante es:  0.35
>     1  billetes/monedas de  0.25
>     El valor restante es:  0.0999999999999
>     1  billetes/monedas de  0.05
>     El valor restante es:  0.0499999999999
>
>     Mi pregunta es, por que al hacer la resta 0.35-0.25 devuelve 0.09
>     y no 0.1?
>
>     Un saludo y gracias 
>
>
> El problema se debe a cómo python y las computadoras en general 
> manejan los números de coma flotante. La respuesta precisa la 
> encontrás en: http://docs.python.org/tutorial/floatingpoint.html

Por cierto, el módulo Decimal fue hecho (entre otros) por Facundo 
Batista, uno de los creadores de PyAr. Muy probablemente también él haya 
escrito o ayudado a escribir ese artículo.

> Las alternativas son utilizar el módulo 'decimal' (from decimal import *),

Es mejor hacer "from decimal import Decimal". Importar con asterisco 
está fuertemente desaconsejado.

> o hacer, por ejemplo, round(3.5-2.5,2).

Yo estoy lejos de conocer los detalles, pero redondear es cambiar el 
tipo de problema, no solucionarlo. De todas maneras ojo, en tu ejemplo 
no hay "ganancia":

 >>> round(3.5 - 2.5, 2)
1.0
 >>> 3.5 - 2.5
1.0

Tampoco la habría con un número no redondo:

 >>> 3.4 - 2.5
0.89999999999999991
 >>> round(3.4 - 2.5, 2)
0.90000000000000002
 >>> round(0.9, 2)
0.90000000000000002
 >>> 0.9
0.90000000000000002


¿cuál es mejor?

Podés manejar más precisión (agregar decimales) y truncar el resultado 
AL FINAL de la operación, pero siempre vas a tener algún grado de error 
de redondeo. Hay mucha literatura al respecto.

Como regla de oro, si es plata (o cualquier cosa donde los decimales 
sean críticos), usá Decimal. Decimal se basa en la representación visual 
del número (que es la que usamos los humanos) y no en la cantidad de 
bits que maneja el silicio por el que transita, por eso se crea a partir 
de una string y no un float.



More information about the pyar mailing list