[pyar] Duda con la resta

Tordek kedrot en gmail.com
Sab Jun 10 20:39:51 ART 2017


Para entender exactamente el problema hay que entender primero la
representación de los decimales; generalmente se usa IEEE754 (y dentro
de ese estandar hay varias variantes, de acuerdo a la cantidad de bits
que uses), y en este caso digamos que son de 32 bits.

Esos 32 se dividen así:

s eeeeeeee fffffffffffffffffffffff

el primer bit indica el signo; los siguientes 8 indican la potencia, y
los ultimos 23 indican el valor del numero.

Esta representacion es similar a la notacion cientifica, como poner
-5.3x10^12, pero se lee: s (1ffff..._2) * 2 ^ (eeee.._2).

(El 1 ese es porque hay un 1 implícito, porque si no habria varias
representaciones del mismo numero, onda "00010 * 2^0" es lo mismo que
"00100 * 2^-1". Igual se complica un poco más por los 0, números
denormalizados, infinitos, nan... pero ignorémoslos por un momento).

Entonces, para representar "2" es fácil:

s = 0 (positivo)
f = 0000...000, con el 1 implicito queda 1000...000 (24b)
e = -22

En total te queda 1....000 * 2^-22, o lo que es equivalente, 1...000_2
>> 22, que es "10" en binario, o sea, 2.

El problema ahora es representar 0.2: Tenés que encontrar un valor
para f y e tal que f*2^e = 0.2, o lo que es lo mismo f/(2^-e),
entonces sabemos que el divisor va a ser una potencia de 2... y no
existe ningún numero (en los 24 bits que tenés) que te permita
representar esto. Lo mejor que podes es aproximar; si escribis...

s = 0
f = [1]100110011001100110011001100
e = -26

tenés un numero que en binario te da 0.001100110011001100110011001100,
que está cerca de 0.2, pero no es igual (porque para representar 0.2
necesitás infinitos digitos despues del 0).

Esta diferencia es el motivo por el que 1 no es igual que 0.1+0.1+...:

1 es

s = 0
f = [1]0....000
e = -23

0.1 es

s = 0
f = [1]100110011001100110011001100
e = -25

0.1 + 0.1 ... arrastra el error de ir sumando
[1]100110011001100110011001100 + [1]100110011001100110011001100 + ...
y terminás con algún 1 entre los bits de f, y el resultado final en
vez de ser [1]0...000 es [1]0...110 (por ejemplo); una diferencia de
2^-40, pero que sigue ahí.


Decimal es una bestia aparte y guarda su representación de otra forma,
que permite evitar la pérdida de precisión, pero no tiene hardware
especializado (en otras palabras, es lento).

Saludos!

--
Tordek

2017-06-10 0:29 GMT-03:00 Alan Jonatan Romero <eldoblecero en gmail.com>:
> Hace siglos que no paso por la lista pero esto me dio curiosidad
>
>
>>>> ...porque el flotante que le estás pasando no es el flotante que vos
>>>> creés... O sea, 2.2 no es 2.2, sino
>>>>
>>>> >>> Decimal(2.2)
>>>> Decimal('2.20000000000000017763568394002504646778106689453125')
>>>>
>>>> Slds.
>>>>
>>>> --
>>>> .    Facundo
>
>
>
> Que explicación o razón tiene esa... "deformación" del decimal que uno le
> pasa? Por qué se comporta de ese modo el método Decimal?
>
>
> _______________________________________________
> Lista de Correo de PyAr - Python Argentina - pyar en python.org.ar
> Sitio web: http://www.python.org.ar/
>
> Para administrar la lista (o desuscribirse) entrar a
> http://listas.python.org.ar/listinfo/pyar
>
> La lista de PyAr esta Hosteada en USLA - Usuarios de Software Libre de
> Argentina - http://www.usla.org.ar


Más información sobre la lista de distribución pyar