miércoles, enero 10, 2007

¿Firebird está loco?

Si alguno de vosotros ha utilizado alguna vez Firebird (la rama Open Source de Interbase), y tenéis la oportunidad, probad esta sentencia, y que alguien me explique por qué el primer campo devuelto tiene el valor 30,680 mientras que el segundo da 30,670.

¿Restar cero a un número puede provocar este tipo de cosas? En fin, aquí va la sentencia. Para mi es algo inexplicable.

SELECT
CAST(1.5 * (20.45 ) * 100 AS INTEGER) / 100,
CAST(1.5 * (20.45 - 0) * 100 AS INTEGER) / 100
FROM una_tabla_cualquiera

Comments:
He procedido con la siguiente orden:

SELECT 1.5 * (20.45 ) * 100 / 100, 1.5 * (20.45 - 0) * 100 / 100;

en Postgresql y obtengo dos resultados exactamente iguales:

30.6750000000000000

Conclusión: pásate a Postgresql ;P

He eliminado los "cast" porque Postgresl hace división entera en ese caso, pero vale para hacerse una idea.
 
Precisamente la historia está en el cast, ya que al convertir a INTEGER, se pierde la parte decimal, y es ahí donde me interesa saber cómo se comportan otros DBMS.

Lo que tengo que hacer es abandonar el BDE en mi proyecto, que me está dando más quebraderos de cabeza que alegrías... jajajaja... pero ya se sabe... es lo que tienen los sistemas "antiguos"... en su día era "lo mejorcito" hahahaaha

Gracias por las pruebas, Davinci!!!
 
En ese caso te comento los resultados con "cast" y posterior división por 100.0 (para forzar la operación con números reales)...

Obtengo lo mismo en ambos casos: 30.68.

Recuerdo que hace algún tiempo leí un artículo que hablaba sobre los principales sistemas de BD libres: Firebird, Postgresql y Mysql. Sí hacían mención a cierta inexactitud del primero con operaciones matemáticas, creo recordar.

Y que haya que estar siempre pegándose con cacharrejos llenos de "abujeros"... ;)
 
Bueno, pues para quien pueda servirle (nunca se sabe quién puede llegar aquí buscando vete tú a saber qué cosa), parece que he topado con una solución medianamente válida a mis problemas de redondeo:

SELECT CAST(CAST(1.5 * 20.45 * 100 AS INTEGER) AS FLOAT) / 100
FROM una_tabla_cualquiera;

1º - Con la multiplicación por cien, pasamos dos decimales a la parte entera.

2º - Con la conversión a INTEGER, descartamos el resto de decimales.

3º - Convertimos a FLOAT, para que la próxima operación se realice con un número en coma flotante.

4º - Se divide entre cien, y se recuperan los dos decimales que pasaron anteriormente a la parte entera.

El problema de esto es que el valor resultante es 30.680000000000000 (muchos ceritos por el final), y si recoges ese valor tal cual, para pegarlo en no se qué sitio de tu aplicación... te puede dar algún que otro disgusto

Probando probando he dado con la que creo que es la solución definitiva (y más increíble todavía):


SELECT CAST(1.5 * 20.45 * 100 AS INTEGER) / 100.00
FROM una_tabla_cualquiera;

Esto devuelve 30.68 como un clavo.

Atentos al ".00", y es que si ponemos tan sólo un cero, es decir, "/ 100.0" en la operación, el resultado será 30.6 (y no 30.7 que en todo caso sería el redondeo de 30.68)

En fin, vaya carajal de operaciones numéricas con firebird...
 
La solución a tu problema es sencilla usa UDF, crea una función que redondee correctamente y listo.
 
Publicar un comentario

<< Home

This page is powered by Blogger. Isn't yours?