Re: YA no se restar!
| From: | Satyam | Date: | Fri, 28 May 2004 08:02:04 +0000 |
| Subject: | Re: YA no se restar! | ||
| References: | 1 | Groups: | php.general.es |
| Request: | Send a blank email to general-es+get-48992@lists.php.net to get a copy of this message | ||
Es por una cuestión de que lo que a ti te parecen numeros redondos, para la
CPU que trabaja en binario no lo son. Por eso, para transacciones
monetarias existen los tipos de datos currency o money que trabajan con una
cantidad limitada de decimales, para que no se acumulen errores de
representación numérica.
Es bastante habitual que si estás queriendo balancear unas operaciones
contables trabajadas sobre variables de tipo numéricas de punto flotante,
siempre te queden fracciones infimas de diferencia.
Lo mejor sería que el lenguaje ofreciera variables con una cantidad fija de
decimales, usualmente dos o tres decimales mas que la cantidad minima a
representar, esto es, para importes con centimos, unos 4 o 5 decimales. De
esta manera, el propio lenguaje trunca automaticamente esas fracciones
sobrantes (imaginate, te esta dando diferencia en la 16a cifra decimal)
Tienes otras dos posibilidades, ambas espantosas. Una es que trabajes con
enteros, escalando las cifras 4 posiciones. La razon de usar dos o tres
decimales por encima de los centimos es para que en operaciones de division,
el resultado se pueda redondear en lugar de simplemente truncar.
La otra alternativa es que uses la funcion de redondeo a dos decimales para
aplicarle a los resultados de las operaciones: round($importe,2) Esta es la
mejor de las dos.
O sea, supon que estas contabilizando los intereses de unas cuentas de
ahorro. Esta es una operacion que te va a dar siempre fracciones decimales
bastante largas (salvo que, de casualidad, la tasa de interes nominal te de
numeros redondos, lo cual es raro). Tras haber hecho el calculo,le haces el
redondeo, y eso es lo que registras. Si no lo hicieras así, veras que
muchas veces, los libros contables no te cierran pues el acumulado de los
intereses pagados a los clientes no coincide con el total de intereses que
sale de la cuenta del banco.
Te pongo un ejemplo simple en decimal. Supon que calculaste que el interes
devengado por un par de cuentas de ahorro ha sido de 0.3333333 que, cuando
lo asientas en la base de datos, dado que usaste un campo de tipo numerico
de dos decimales, queda registrado como 0.33. El acumulado de los intereses
pagados en esas cuentas, que fuiste llevando en memoria, te da 0.666666666,
con tantos decimales como PHP lleve. Cuando asientas este acumulado en los
libros, el redondeo lo lleva a 0.67. Ahora vas a balancear los libros con
una consulta de SQL, algo asi como Select sum(Debe), sum(Haber) from......
y el caso es que te da un centavo de diferencia. Los clientes recibieron
0.66 de intereses entre los dos, al banco le figura que pagó 0.67. Hace
unos 30 años un programador de un banco fue acumulando en su cuenta las
diferencias y se hizo una fortuna. Desde entonces existen normas para
evitar estos 'errores'.
Satyam
----- Original Message -----
From: "Innox - Juan Carlos Gonzalez" <jgonzalez@innox.com.mx>
To: "phpes" <php-es@lists.php.net>
Sent: Friday, May 28, 2004 1:12 AM
Subject: [PHP-ES] YA no se restar!
>
> Jóvenes!! AYUDA!!!
>
> // código
> echo "a = $a, b = $b\n";
> echo "resta = ".($a-$b);
>
> // resultado
> a = -0.1, b = -0.1
> resta = 3.60822483003E-16
>
> Yo se que es un problema común... también se que alguien ha tenido ese
> problema y lo solucionó.
>
> GRACIAS!
>
> --
> Atentamente,
>
> Juan Carlos González
> Innox - Innovación Inteligente
> +52 (33) 3615 5348
> jcgonz@innox.com.mx
> http://www.innox.com.mx
>
> --
> PHP Spanish Localization Talk Mailing List (http://www.php.net/)
> To unsubscribe, visit: http://www.php.net/unsub.php
>
>