Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Bases de datos > Firebird e Interbase
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 28-04-2014
Avatar de mlara
[mlara] mlara is offline
Miembro Premium
 
Registrado: jun 2003
Ubicación: Colombia
Posts: 667
Poder: 21
mlara Va por buen camino
Interpretación de tipo de dato flotante

Hasta hoy varias veces tuve que lidiar con un caso bastante particular relacionado con los tipos de datos de punto flotante en aplicaciones Delphi + Firebird. Casi al final de la historia, por supuesto realizando ciertas consideraciones importantes, opté por trabajar en Firebird con el tipo DOUBLE PRECISION. En la documentación se señala que a diferencia del tipo de dato FLOAT, este tiene un tamaño de 64 bits y no de 32 bits, con una precisión de 15 dígitos, y no de 7 dígitos. De esta forma nunca tuve inconveniente alguno en particularmente almacenar o recuperar valores reales.

DOUBLE PRECISION: 64 bits(a), 2.225 x 10^-308 to 1.797 x 10^308, IEEE double precision (15 digits)
FLOAT: 32 bits, 1.175 x 10^-38 to 3.402 x 10^38, IEEE single precision (7 digits)
NUMERIC(p, s): 16, 32, o 64 bits (variable)
DECIMAL(p, s): 16, 32, o 64 bits (variable)

(a) El tamaño de DOUBLE es dependiente de la plataforma*. La mayoría de las plataformas soportan el tamaño de 64 bits.

* No se refiere a si la plataforma es de 32 o de 64 bits. La respuesta a la pregunta ¿Qué plataformas no soportan el tamaño de 64 bits para el tipo de dato DOUBLE de Firebird? en realidad hasta este momento no la conozco.

Y a qué viene todo esto? Bueno, hace poco llegó un cliente con un equipo en el que un sistema desarrollado por mí no funcionaba correctamente al realizar operaciones comunes. Al realizar las pruebas respectivas encontré muy extraño el caso, más aún porque se trataba de un error no esperado en un consulta extremadamente simple. Para poder reproducir el error estando muy seguro de que la causa no era mi implementación de la base de datos, quise hacerlo todo desde cero:

Código SQL [-]
CREATE TABLE Testing (F1 DOUBLE PRECISION)

Código SQL [-]
INSERT INTO Testing VALUES(1.25);
INSERT INTO Testing VALUES(0.05);
INSERT INTO Testing VALUES(3.8);
INSERT INTO Testing VALUES(8.999);

Luego, al realizar la consulta de cada registro de forma independiente, así:

Código SQL [-]
SELECT * FROM Testing WHERE F1 = VALOR

, sucede que sólo funcionaba para el primer registro, es decir para VALOR = 1.25. Cuando VALOR era igual a 0.05 o 3.8 u 8.999 no se obtenía resultado alguno, o dicho de otra forma, se obtenía un conjunto vacío. La única forma de hacer que funcionara para los demás registros fue realizando la consulta de esta forma:

Código SQL [-]
SELECT * FROM Testing WHERE F1 = CAST(VALOR AS DOUBLE PRECISION)

Al final, y para saber si tenía algún problema con un equipo en particular, no fuera que me llegase después algún caso parecido, realicé esta consulta:

Código SQL [-]
SELECT IIF(8.99 = CAST(8.99 AS DOUBLE PRECISION), 1, 2) FROM RDB$DATABASE

El resultado esperado es 1, pero si se trata del mismo caso del cliente en cuestión, se obtendrá un 2.

Por supuesto que realicé el mismo ejercicio en varios equipos. En todos no hubo problema alguno, excepto en el equipo del cliente. ¿Qué tiene de especial? No lo sé en verdad. Se trata de un portátil HP G42 con procesador Intel Core i3 M350 a 2.27 GHz con 3 GB en RAM, sistema operativo Windows 7 Home Basic de 32 bits ejecutando una aplicación con Firebird embebido versión 2.1.4.18393.

Lo único que se me ocurre es que el equipo del cliente sea una de esas plataformas que no soporta el tipo de dato DOUBLE PRECISION de 64 bits, de tal forma que al realizar Firebird la conversión internamente no se obtenga el resultado esperado. Hay que recordar que este post lo inicio afirmando que antes tuve inconvenientes con los tipos de datos de punto flotante de 32 bits.

Decidí compartir este caso ya que estuve consultando y no encontré información alguna al respecto, y de haber alguien que sepa exactamente qué sucede seguramente además de mí alguien agradecerá su aporte.
__________________
...y mañana caminaré por las calles pasando inadvertido, como siempre.

Última edición por mlara fecha: 28-04-2014 a las 23:01:01.
Responder Con Cita
  #2  
Antiguo 28-04-2014
Avatar de mamcx
mamcx mamcx is online now
Moderador
 
Registrado: sep 2004
Ubicación: Medellín - Colombia
Posts: 3.911
Poder: 25
mamcx Tiene un aura espectacularmamcx Tiene un aura espectacularmamcx Tiene un aura espectacular
Es un problema basado en 2 cosas:

1- Matematicas:

0.9999... == 1

2- Binario:

Los numeros float se guardan en base-2, en vez de usar base-10. Eso significa que las matematicas que usan (usualmente) los lenguajes NO ES la que aprendiste en la escuela.

Puedes aprender mas, y es algo, junto a lo de unicode y el manejo de fechas, que TODO programador debe saber:

http://floating-point-gui.de/

Y

http://programmers.stackexchange.com...-pitfalls?rq=1
__________________
El malabarista.
Responder Con Cita
  #3  
Antiguo 29-04-2014
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.040
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Aparte de lo comentado por mamcx, algo que todo programador debe saber y que se aprende cuando te encuentras con el problema, es recomendable que cambies todos tus datos a numeric, siempre que se traten de valores, precios, cantidades, etc. y acabarás con el problema.
Responder Con Cita
  #4  
Antiguo 29-04-2014
Avatar de mlara
[mlara] mlara is offline
Miembro Premium
 
Registrado: jun 2003
Ubicación: Colombia
Posts: 667
Poder: 21
mlara Va por buen camino
No sé, pero recordé una ocasión en la que pedí que no me hablaran de Firebird cuando abordé un caso relacionado con InterBase, y no faltó quien lo hizo. Acaso la solución era migrar todo un sistema con miles de líneas de código fuente y una implementación de base de datos que usaba y explotaba características propias de InterBase? Quiero decir con esto, y volviendo al tema, que creo las respuestas no son del todo apropiadas ya que no abordan el tema tal y como está planteado, razón por la cual voy a intentar explicarlo de otra manera, para lo cual parto nuevamente desde el comienzo:

La sentencia:

Código SQL [-]
SELECT IIF(8.99 = CAST(8.99 AS DOUBLE PRECISION), 1, 2) FROM RDB$DATABASE

, si la probamos en todas las instalaciones de Firebird y equipos que queramos, nos debe dar como resultado 1, cierto?

Veamos: el número 8.99 tiene su forma binaria tanto en 32 bits como en 64 bits (la podemos ver aquí: http://www-2.dc.uba.ar/materias/oc1/...at_conver.html)

Si voy a la representación binaria de precisión simple (32 bits) y luego hago la conversión nuevamente a punto flotante obtengo el número: 8.9899998

Si voy a la representación binaria de precisión doble (64 bits) y luego hago la conversión nuevamente a punto flotante obtengo el número: 8.99

Son diferentes, por supuesto. Ahora, si observamos nuevamente la consulta la pregunta es: aún esperamos 1 como resultado? Yo diría que sí, o acaso 8.99 no es igual a 8.99? Aún haciendo uso del CAST en el segundo.

Pero no nos apresuremos...

Obviamente Firebird hará internamente las conversiones del caso para poder comparar los números expresados en forma binaria (o hexadecimal). Entonces, si supongo que el CAST obliga a Firebird a expresar el 8.99 con precisión doble (de 64 bits), qué pasa con el primer 8.99, que no tiene CAST? Se expresará como un dato de punto flotante con precisión simple? Firebird lo "elevará" y expresará como un dato de punto flotante de precisión doble, dado el tipo de dato del número al lado derecho en la expresión condicional?

Antes de continuar, quiero recordar que la exposición del tema se debe a que, al ejecutar la consulta de este post en "mil computadores" ... obtengo un 1 como resultado, menos en uno de ellos. Qué sucede en ese equipo?

Ahora, si a esto le sumamos el hecho de que el sistema en cuestión viene funcionando hace más de 10 años y que se trata de un sistema robusto, en producción, usado por muchos clientes que nunca han tenido problemas en este sentido, la solución obviamente no es morirse cambiando los tipos de datos DOUBLE PRECISION a NUMERIC, salvo que todas las plataformas del mundo hubiesen "mutado" misteriosamente y de repente todo funcionara mal (hago la salvedad de que esto sí podría ser posible si alguna actualización del sistema nos quisiera hacer pasar un mal rato).
__________________
...y mañana caminaré por las calles pasando inadvertido, como siempre.

Última edición por mlara fecha: 29-04-2014 a las 16:46:45.
Responder Con Cita
  #5  
Antiguo 29-04-2014
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.040
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Es que no tiene nada que ver con firebird o interbase. Es igual en todos los sistemas.
Responder Con Cita
  #6  
Antiguo 29-04-2014
[egostar] egostar is offline
Registrado
 
Registrado: feb 2006
Posts: 6.556
Poder: 25
egostar Va camino a la fama
Cita:
Empezado por mlara Ver Mensaje
Antes de continuar, quiero recordar que la exposición del tema se debe a que, al ejecutar la consulta de este post en "mil computadores" ... obtengo un 1 como resultado, menos en uno de ellos. Qué sucede en ese equipo?
Me pregunto si el microprocesador es la diferencia, es decir AMD vs INTEL.

Digo a este punto cualquier cuestión es válida.

Saludos
__________________
"La forma de empezar es dejar de hablar y empezar a hacerlo." - Walt Disney
Responder Con Cita
  #7  
Antiguo 29-04-2014
Avatar de mlara
[mlara] mlara is offline
Miembro Premium
 
Registrado: jun 2003
Ubicación: Colombia
Posts: 667
Poder: 21
mlara Va por buen camino
A veces cuando quiero hablar de si las cosas son o no son me voy a la taberna... Casimiro, de qué se trata esto? Yo expongo un caso que me parece interesante discutir. Podría plantear las cosas de otra manera, podría preguntar de qué manera Firebird hace las conversiones, y luego las comparaciones? De qué depende? Y no todos los sistemas o los lenguajes o sistemas las hacen igual, pero no quiero desviarme del tema. Al final sólo creo que el tema podría tratarse de verdad, un poco en profundidad.
__________________
...y mañana caminaré por las calles pasando inadvertido, como siempre.

Última edición por mlara fecha: 29-04-2014 a las 17:42:28.
Responder Con Cita
  #8  
Antiguo 29-04-2014
Avatar de mlara
[mlara] mlara is offline
Miembro Premium
 
Registrado: jun 2003
Ubicación: Colombia
Posts: 667
Poder: 21
mlara Va por buen camino
egostar, yo diría que no tiene nada qué ver con el procesador. Aún así en el primer post de este hilo expuse las características del equipo en el que sucede.
__________________
...y mañana caminaré por las calles pasando inadvertido, como siempre.
Responder Con Cita
  #9  
Antiguo 29-04-2014
Avatar de mamcx
mamcx mamcx is online now
Moderador
 
Registrado: sep 2004
Ubicación: Medellín - Colombia
Posts: 3.911
Poder: 25
mamcx Tiene un aura espectacularmamcx Tiene un aura espectacularmamcx Tiene un aura espectacular
Puede que si:

http://randomascii.wordpress.com/201...-compare-them/

Mas detalles en:

http://randomascii.wordpress.com/201...int-precision/

En resumen:
Cita:
IIF(8.99 = CAST(8.99 AS DOUBLE PRECISION), 1, 2)
Es una comparación/afirmación incorrecta. Por eso te puse el link de http://programmers.stackexchange.com...-pitfalls?rq=1 donde se muestra que seria mejor que los lenguajes no implementaran la igualdad para floats.

Tambien ahi estaba:

Cita:
Warning: The floating-point type System.Double lacks the precision for direct equality testing.
Que no es firebird pero da una idea.

En el momento que hay un float, no esperes resultados predecibles si cambias de compilador, CPU o arquitectura, a menos que uses una libreria que de esas garantias.

Por ejemplo en:

http://gafferongames.com/networking-...t-determinism/
Cita:
People even report different results on the same machine from run to run, and between debug and release builds. Other folks say that AMDs give different results to Intel machines, and that SSE results are different from x87. What exactly is going on? Are floating point calculations deterministic or not?

Unfortunately, the answer is not a simple “yes” or “no” but a resoundingly limp “maybe?”
Y si, lo de Casimiro es correcto. Si un tipo de datos te falla, entonces la solución es cambiarlo. Si se supone que estas haciendo cálculos financieros inevitablemente usa un tipo de dato money/decimal o almacena como INTEGER los valores y aplica las formulas correctas para ese caso -y asegurate de usar exactamente el mismo tipo a lo largo de toda la cadena de computación, osea, si en FB usas NUMERIC que en Delphi tengas el equivalente!-.

----
Es divertido saber que los aspectos fundamentales de la programación son así de confiables
__________________
El malabarista.

Última edición por mamcx fecha: 29-04-2014 a las 18:11:21.
Responder Con Cita
  #10  
Antiguo 29-04-2014
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.040
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Cita:
Empezado por mamcx Ver Mensaje

Muchas veces sí estoy de acuerdo contigo

Última edición por Casimiro Notevi fecha: 29-04-2014 a las 19:17:28.
Responder Con Cita
  #11  
Antiguo 29-04-2014
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.040
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Cita:
Empezado por mlara Ver Mensaje
...
Es que me ocurrió lo mismo que a ti. Cientos de clientes (por no decir miles ), después de muchísimos años, sin problemas. Y un día un cliente tiene un problema extraño, no le "cuadraban" unos datos que a todo el mundo le funcionaba bien. Siguiendo paso a paso nos encontramos con que la comparación con valores double no se hacía correctamente en según qué circunstancias. La solución es sencillamente cambiar double por numeric.
En nuestro caso fue fácil porque siempre he usado dominios para declarar los campos de las tablas, así que solamente se tuvo que cambiar la declaración de algunos dominios y no hubo que tocar los campos.
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
tipo de dato arnedokpo Conexión con bases de datos 1 14-07-2008 16:37:06
Tipo de dato nelem Internet 4 15-01-2008 16:46:06
Tipo de Dato BetoAlonso Varios 11 09-12-2007 00:30:01
Caso Raro de Decimales en campo de tipo Flotante AGAG4 Conexión con bases de datos 5 21-02-2007 18:27:46
ayuda con numeros de tipo flotante vero_17jm SQL 3 07-12-2006 14:06:51


La franja horaria es GMT +2. Ahora son las 23:16:35.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi