viernes, 29 de enero de 2010

Problema de precisión con el punto flotante en java (y en otros)

Estaba un día un amigo javero programando como cotidianamente lo hace, feliz en por la vida, cuando, de repente, al comprobar una igualdad en un algoritmo que parecía más que lógica se encontró con que algo no estaba funcionando como debiera.

En sí se trataba de una igualdad entre números de punto flotante, de tipo double  para ser más exacto (o doble si quieres usar una traducción literal, pero esto es programación, así que te quiero pedir que mejor no lo hagas, puede provocar confusiones). Como se trataba de una operación algo mas específica y seguramente compleja como para ponerla de ejemplo, mejor me remitiré al fragmento de código java que éste amigo me proporcionó para ejemplificar lo que pasa:
double test = 0.0;
for (int i = 0; i < 10; i++)
    test += 6111403.6;

//6111403.6 sumado 10 veces debería ser 61114036.0

//se agrega cero después del punto, así java lo toma como tipo double

if (test == 61114036.0)
    System.out.print("Igual");

else
    Syste.out.print("WTF!!??");

Consultando el valor de la variable 'test' al final nos da: ­test=6.111403600000001E7 en lugar de un varlor de 6.1114036E7 .... ¡así es, algo totalmente inesperado!

¿Pero qué es lo que sucede? bueno, veamos, los números de punto flotante (o coma flotante como le dicen en tierras del mediterráneo) se crearon con la intención de representar números reales. Un número de punto flotante se representa exactamente por la fórmula:
digitos significantes × baseexponente
y al parecer en nuestro problema algo tiene que ver la precisión que manejan los números de punto flotante  en su representación en sistemas informáticos (en la computadora).

Entonces la presición depende de que tantos valores se puedan almacenar de cada una de las partes de la fórumula de arriba, lo cual en ambientes informaticos, como todos saben, es finito, delimitado por el tipo de dato que se utilize para representar ese número real.

Entonces el hecho real es que los números de punto flotante no pueden representar absolutamente todos los números reales, entonces las operaciones que en ellos realizamos nos pueden llevar a situaciones sorpresivas como la que arriba ejemplificamos. Todo esto debido a la presición finita que las computadoras usan para representar estos números.


Para más información al respecto puedes consultar el articulo en la Wikipedia aqui.

Continuando con la historia, lo que mi amigo javero hizo para solucionar su problema, como le bastaba una presición con respecto a los primeros dos dígitos decimales, fue algo como lo siguiente con el valor en cuestión:
test = Math.round(test * 100) / 100;
de esta manera ya lo pudo comparar de manera confiable. Cada quien podrá implementar la manera que mejor le convenga, lo que si hay que conservar en mente, esque este tipo de problemas se pueden presentar en cualquier momento si estamos trabajando con valores de punto flotante, por lo tanto debemos tomar medidas si vemos que hay riesgo potencial de que ello signifique errores en nuestros sistemas.

Hay otras alternativas para evitar este problema, una explicación (que además esta en español pero no precisamente para java) se puede ver aqui.

Espero no haber confundido más con respecto a este tema y te sea de alguna utilidad, cualquier comentario aqui estamos...  ¡Paz!

lunes, 25 de enero de 2010

Jetty: Servidor Web embebido

Navegando un día buscando precisamente algo de esas cosas embebidas (esa palabra me sigue causando algo de conflicto pero si existe en el español, ¡¡lo juro!!) me encontré con algo llamado Jetty. Jetty nos proporciona, entre varias cosas,  un servidor HTTP, cliente HTTP, y un contenedor de servlets de java. Jetty además es otro proyecto cuyo código es abierto, y esta disponible para su distribución y uso comercial. El núcleo del proyecto se encuentra alojado por la Fundacion Eclipse a partir de la versión 7 y de las versiones 6 para abajo en Codehaus.

Varios proyectos interesantes ya usan Jetty. Nosotros lo hemos utilizado como servidor embebido incluso migrando directamente proyectos que corren bien usando un contenedor Tomcat, en Jetty funcionan bastante bien. Al igual que lo que comentaba de Derby, el utilizar este tipo de herramientas embebidas hace ampliar las posibilidades en aplicaciones que se ejecutan en diferentes ambientes y diferentes equipos, es ligero y confiable. Para ver esa posibilidad de utilizar Jetty de manera embebida puedes ver el tutorial aqui.

En realidad solo quería comentar un poco a cerca de esta aplicación, la documentación que ofrece es bastante clara, con ejemplos de código que ayudan poniendo énfasis en los puntos importantes del tutorial en línea, claro, en ingles. Así que si quieres echar un vistazo a Jetty te invito a checar su página principal http://jetty.codehaus.org/jetty/.

viernes, 22 de enero de 2010

Iniciandose en Derby: Java DB

Derby es un subproyecto de Apache DB. Se trata de un manejador de base de datos de código abierto hecho completamente en java. Derby tiene varias características que lo hacen sumamente atractivo para soluciones en sistemas ligeros. Entre otras me gustaría mencionar las que a mi me llamaron la atención: es fácil de instalar, ligero (pesa tan solo unos cuantos megabytes) y puede usarse de manera embebida (palabra que si existe en español, ver aquí), es decir, que dentro de una aplicación java, podemos iniciar y utlizar bases de datos de Derby dentro de la misma máquina virtua.


Bueno, después de esta pequeña reseña que podemos encontrar fácilmente en cualquier sitio que hable de Derby, vamos a lo importante, como lo usamos dentro de nuestras aplicaciones.

Básicamente lo que haré a continuación será parafrasear un poco los ejemplos de la guía rápida básica de Derby que podemos encontrar en el tutorial oficial.

Primero que nada necesitamos descargar Derby por supuesto, lo cual se puede hacer aquí. Una vez descargado descomprimimos el directorio que esta ahí contenido, ejemplo 'db-derby-alguna_version-bin'. A la ubicación de este directorio lo llamaremos de ahora en adelante: DERBY_HOME.

Comenzaremos con el ejemplo de el uso de Derby embebido dentro de tu aplicación java, lo hago debido a que esta es una de las características que mas llaman la atención de este manejador. Se supone que ya tenemos instalado y debidamente configurado un jdk en nuestro equipo.

Lo haremos a través de la linea de comandos (unix y windows) para hacer mas sencillo de explicar el procedimiento.

Primero creamos un directorio que llamaremos "DERBYTUTOR" y entramos en él. Ahí introduciremos los sguientes comandos, no se te olvide el punto que va al final (.):
Unix:
cp $DERBY_HOME/demo/programs/workingwithderby/* .

export CLASSPATH=$DERBY_HOME/lib/derby.jar:.

 Windows:
copy %DERBY_HOME%\demo\programs\workingwithderby\* .

set CLASSPATH=%DERBY_HOME%\lib\derby.jar;.

Ahora en el directorio DERBYTUTOR en donde nos encontramos deben existir varios archivos java. Después de confirmar que los archivos WwdEmbedded.java y WwdUtils.java existan e introducir el siguiente comando para compilar ambos archivos:

Unix y Windows:
javac WwdEmbedded.java WwdUtils.java
Si en este punto ocurre algún error probablemente es porque no se tiene bien configurado el jdk en nuestro sistema o que al definir el classpath algo no se hizo correctamente.

Si todo salió bien no deberá aparecer nada al ejecutarse la linea anterior y los archivos se habrán compilado satisfactoriamente, creando los archivos WwdEmbedded.class y WwdUtils.class.

A continuación ejecutamos el ejemplo con el siguiente comando y sucederá algo como lo que sigue:

java WwdEmbedded 
org.apache.derby.jdbc.EmbeddedDriver loaded.
Connected to database jdbcDemoDB
 . . . . creating table WISH_LIST
Enter wish-list item (enter exit to end):
a peppermint stick
  __________________________________________________________
On 2009-05-08 13:12:09.058 I wished for a peppermint stick
  __________________________________________________________
Enter wish-list item (enter exit to end):
a long vacation
  __________________________________________________________
On 2009-05-08 13:12:09.058 I wished for a peppermint stick
On 2009-05-08 13:12:21.28 I wished for a long vacation
  __________________________________________________________
Enter wish-list item (enter exit to end):
exit
Closed connection
Database shut down normally
Getting Started With Derby JDBC program ending.

¿Que sucede aquí? Estamos accediendo una base de datos Derby embebida he insertando datos en una tabla. Asi es, sin un servidor Derby activo, simplemente con la aplicación actual.

En el enlace del ejemplo podrás obtener más detalles, lo único que me gustaría comentar aquí es como se logra la conexión en la clase WwdEmbedded a través de que detalles.

Lo único que cambia, con respecto al uso de cualquier JDBC es que utiliza los siguientes parametros:
   // define driver a usar (el contenido en la libreria derby.jar)
      String driver = "org.apache.derby.jdbc.EmbeddedDriver";
   // nombre de la base de datos 
      String dbName="jdbcDemoDB";
   // URL que Derby usara
      String connectionURL = "jdbc:derby:" + dbName + ";create=true";

Y con esto simplemente creamos la conexión de manera normal:

String driver = "org.apache.derby.jdbc.EmbeddedDriver";
...
try {
    Class.forName(driver); 
} catch(java.lang.ClassNotFoundException e) {
  ...
}
String connectionURL = "jdbc:derby:" + dbName + ";create=true";
...
try {
    conn = DriverManager.getConnection(connectionURL);
    ...  
}  catch (Throwable e)  {   
   ...
}

 Aquí concluiría este blog, cualquier otra duda te invito a checar la documentación de los ejemplos, es bastante clara (Aunque en inlgés) y para fines prácticos yo la veo bastante útil.

Puedes ver el sitio oficial de Derby aqui.

Inicia Bitacora de un Javero y otras cuestiones


HOla! Este blog comienza por la necesidad de llevar una bitácora de cosas que ocurren en la vida diaria para un programador cualquiera. En el pasado cuando he tenido algunas inquietudes, ya sabes, esos problemas que necesitas resolver en algún sistema que estés desarrollando y que no encuentras alguna solución puntual en un lugar en específico; ese tipo de inquietudes que cuando logras resolver piensas que a alguien mas podrian serle de utilidad, me ha llevado a iniciar este esfuerzo. También es una manera de llevar un registro de cosas que luego se puedan olvidar, jeje... porque a todos nos pasa, mas vale un blog tonto que una mente lista, a veces.

El nombre de este blog esta obviamente relacionado con el lenguaje de programación Java, con el cual convivo diariamente, sin embargo, debido a que siempre es necesario de otras herramientas o trabajar en otros contextos, será común encontrar temas que puedan estar relacionados con el lenguaje o no directamente. Habrá ocaciones que se hable de sistemas operativos, noticias de tecnología, frameworks, IDE's, juegos, diseño, internet, etcétera; no te preocupes si nos desviamos un poco del tema principal, habrá algún nexo con nuestra intención principal, simplemente la tecnología, sea tangible o intangible.

Bueno si es tu intención a aportar en este blog eres bienvenido, cualquier comentaro, sugerencia o corrección para una probable "fe de erratas" (o fe de ratas como le suelen decir) será también bienvenido, asi que "nieve para el Popocatepetl"... y comenzamos.