sábado, 13 de diciembre de 2008

Compresión de Fecha para Identificador

En cierta ocasión requerí un procedimiento para obtener identificadores de transaccion únicos en un ambiente distribuido. Existieron ciertas atenuantes que me hicieron más sencilla la planeación del proceso, como el hecho de que los nombres de red y de usuarios de los equipos son rigurosamente controlados, razón por la cual yo podía despreocuparme completamente de ello, e incluso utilizarlos como parte de la creación del identificador.

Se me ocurrieron varios métodos pero en todos ellos se incurría en una probabilidad de colisión de identificador (colisión = repetición). Una limitante que sí tenía era que este identificador único debía caber en solo 12 caracteres, PERO..., no podía utilizar 4 de esos caracteres porque contienen caracteres que son absolutamente necesarios para la identificación de la transacción, así que me quedaban solo 8.

Pensando y pensado, se me ocurrió que podría utilizar una fecha en formato DD-MM-YY-HH:MI:SS (sin los guiones ni los dos puntos) añadiendo además 2 números al azar. Pensé también en utilizar números al azar para el identificador completo pero lo deseché puesto que la fecha es mucho más descriptiva para mis fines.

Asi pues teniendo la siguiente fecha: 13120811341763, me inventé un procedimiento para dejarla de 14 en tan solo 8 caracteres y quedó así luego de la "compresión" : Y0KS4hm

¿Se ve difícil la cosa eh?, pues no lo es tanto. ¿Recuerdas los números hexadecimales?. Pues bien, recordarás que el 12 decimal se expresa como una simple C. Como verás... allí nos ahorramos un dígito ya que necesitamos solo un caracter para escribir un número de dos caracteres. Utilizando eso como base la idea se trata de realizar un cambio de base decimal a otro de manera que el resultado caiga en la utilización de menos caracteres.

En mi caso utilicé un "sistema numérico" de base 55, los caracteres fueron: del 0 al 9, de la A a la Z y posteriormente en minúsculas hasta llegar a un total de 55. De esa manera, al convertir la "fecha" expresada en base decimal pero contenida en una cadena (13120811341763) a otro número en base 55 contenido también en una cadena el resultado es la misma cadena pero "comprimida".

domingo, 9 de noviembre de 2008

Añadir Minutos a TimeStamp en Firebird

Me encontraba moviéndole un poco al Firebird y resultó que necesito añadir X cantidad de minutos a la información contenida por una columna de tipo TimeStamp. Lo lógico era utilizar la unidad 1/3600 para obtener el decimal correspondiente a los minutos (como en cualquier otro DMBS), sin embargo, los intentos fueron infructosos ya que la operación no se ejecutaba correctamente.

Casi desesperado, recordé que debía poner ".0" a los números para que los tomara como decimales y no como enteros. Al realizar lo anterior me encontré que aunque las divisiones las realizaba correctas, solo funcionaban hasta cierta cantidad de decimales. Posteriormente encontré que por lo menos para las fechas, debía escribir el número resultado de la división para encontrar el valor decimal de los minutos en lugar de realizar la división dentro de la consulta, de manera que si quiero añadir 5 minutos a la fecha actual debo utilizar un query como el que aparece a continuación y en el que podrán ver el resultado de utilizar los dos métodos:

select current_timestamp,
current_timestamp+(1.0/3600.0)*5.0 as incorrecto,
current_timestamp+(0.0006944445*5.0) as correcto
from rdb$database;



La versión de Firebird que estoy utilizando es la 2.0 y es donde el query funciona como lo indico, es decir, que falla al realizar la división. Sin embargo, leo por allí que en la versión 2.1 ya han añadido funciones para trabajar más fácilmente con las fechas así como otro montón de funciones básicas que francamente me extraña que no hubieran sido añadidas anteriormente. Algunas de ellas las comentan en el Blog de Johny Suárez.

Las versiones 2.1 de Firebird (embedded, ADO.NET y Server) las pueden encontrar en el sitio de Firebird/IbPhoenix.

Debo comentar que tras haberlas instalado, y reiniciado mi computadora =) la base de datos y el query han funcionado sin problema. Podrían probar con este

select current_timestamp,
current_timestamp+(1.0/3600.0)*5.0 as incorrecto,
current_timestamp+(0.0006944445*5.0) as correcto,
dateadd(SECOND,5,current_timestamp) as mas_correcto
from rdb$database;

Espero que este pequeño post les sirva para ahorrarse dolores de cabeza: recuerden utilizar las versiones más actuales, checar diferencias entre versiones, y si van a realizar un cambio en una base de datos en producción pues hay que tomar las precauciones de necesarias antes de realizar el cambio tales como crear una copia de respaldo de nuestros datos y configuración.

sábado, 1 de noviembre de 2008

Firebird, DBMS con capacidad Embedded

Para una aplicación que estoy por comenzar a desarrollar, necesito algún DMBS (database management system) relacional con procedimientos almacenados y que no tenga limitaciones en su versión gratuita (como algunos que establecen un máximo de 2 ó 4 GB de capacidad), y que además fuera posible utilizarlo “embebido”, esto es, que para utilizarlo no fuera necesario instalar nada en la computadora del usuario final.

Hablemos pues un poco acerca de Firebird, sus inicios y porqué lo elegí. Recordé que en mis años mozos por allá del año 2001 utilizaba Delphi + Interbase 6 (Lenguaje de Programación + DBMS, ambos de Borland), cuando interbase era OpenSource. No recuerdo en qué año pero Borland decidió cerrar la rama OpenSource de Interbase y con ello Interbase volvió a ser un DBMS propietario.

Tras el cierre del proyecto OpenSource Interbase por parte Borland, hubo personas que decidieron continuar con la rama de desarrollo y pusieron manos a la obra, retomaron los fuentes, establecieron un punto de inicio y el proyecto fue renombrado como Firebird.

Grandes avances se han realizado desde entonces, éste DBMS OpenSource ya soportaba procedimientos almacenados cuando MySql todavía estaba soñando con ello. Sinceramente considero que a Firebird le ha faltado la promoción que se le ha dado a MySql.

¿Porqué lo necesito embebido?, la respuesta es sencilla, no me puedo poner a decirle a los usuarios que primero tienen que instalar MySql, Oracle Express, Sql Server Express o cualquier otro y luego indicarles como configurarlo, eso podría hacerlo con una empresa, pero al usuario final que no es empresa le resultará tedioso y finalmente será un obstáculo para la adquisición de la aplicación puesto que tendrán temor de “poner algo mal” y que se vaya al traste su Computadora.

En fin, ¿Cómo utilizar Firebird como DBMS embebido?. En realidad es muy sencillo. Por lo menos es muy sencillo en .NET que es el lenguaje voy a utilizar para realizar la aplicación.

Solo es necesario visitar la página del proyecto Firebird en .NET, y allí encontrarás los archivos del servidor, el embedded Server y el DataProvider para .NET así como ejemplos y documentación.

Ahora, solo es necesario bajar los archivos del embedded Server y el DataProvider, copiar al directorio “bin” de tu aplicación los archivos fbembed.dll, icudt30.dll, icuin30.dll y icuuc30.dll que se encuentran todos ellos dentro del archivo que bajaste acerca del embedded Server, poner una referencia al FirebirdSql.Data.Firebird.dll en tu programa de .NET y ¡listo! ya puedes realizar aplicaciones con acceso a base de datos sin que tu usuario final tenga que instalar absolutamente nada acerca de ese DBMS.

Luego de lo explicado en el párrafo anterior ya estás en condiciones de programar en .NET como lo harías hacia cualquier otro DBMS.

Un comentario: en versiones anteriores del embedded Server solo era necesario copiar el fbembed.dll pero en la nueva versión 2.0.1 ya es necesario copiar todos los archivos que indiqué.

Para finalizar debo indicar que es posible utilizar Firebird como un servidor tradicional, esto es, instalar un servidor que correría como un servicio del sistema y al que pueden conectarse múltiples computadoras (Firebird Server).

Si te interesa documentarte acerca de Firebird, el siguiente link te llevará a la página del proyecto. Busca las “Quickstart guide” ya que en ellas encontrarás información básica como sintaxis, instalación y ayuda. Y en el siguiente encontrarás unas CheatSheet acerca de Firebird.


miércoles, 10 de septiembre de 2008

Cálculos con números de más de 300 dígitos

Tal vez en alguna ocasión hayas leído que los cálculos del número Pi han llegado hasta aproximaciones de varios miles de dígitos decimales, y tal vez hayas intentado calcularlos. Sin embargo los tipos de datos primitivos como el float en Java ó el Double en .NET, con rangos de números flotantes que pueden tener un rango de unos 300 dígitos decimales, sin embargo, como números flotantes que son, se pierde precisión.

¿Cómo resolver entonces una multiplicación ó suma que implique más de 300 dígitos?. Veamos en este Post un método sencillo pero muy interesante para realizar éste cálculo.

El cálculo de Pi y otros números irracionales como e (y de otros muchos números) tienen complicaciones debido a la cantidad de decimales. Incluso si el número es un entero, por ejemplo quieres multiplicar un número muy muy grande, digamos cantidades de átomos o moléculas o cualquier otra cosa.

Digamos que queremos multiplicar un número de 50 dígitos por otro de 70 dígitos. Dado que no “caben” en los tipos de datos primitivos de ningún lenguaje de programación tendremos que inventarnos un método para realizarlo, esto es, “enseñar” a la computadora a multiplicar de manera un poco diferente a la que realiza. El ejemplo está en pseudocódigo y al final el código en VB.NET, aunque el pseudocódigo es bastante claro y podría ser convertido fácilmente a Java aunque por falta de tiempo en esta ocasión solo lo dejaré en VB.NET y otros (se aceptan colaboraciones).

Las premisas de las que partimos son:
1) que los números con los cuales vamos a operar están almacenados en variables de tipo cadena (String).
2) Que iremos sumando dígito a dígito, para ello tomaremos el dígito, lo convertiremos a número utilizando funciones de conversión de String a Integer (o similar)

La manera tradicional de sumar se explica en las siguientes imágenes.

En la primera imagen (658+231=889) podemos ver que los dígitos se van sumando uno a uno comenzando por el menos significativo (las unidades) y en el esquema está bastante claro el orden y las sumas en cada paso para conformar el resultado final.


En la segunda imagen (769+35=804) podemos ver que:
1) necesitamos que los números tengan igual longitud, y la menos complicada de explicar me pareció que es la de añadir ceros al inicio de la cadena que sea más corta de manera que las dos cadenas (que contienen los dígitos) tengan la misma longitud.

2) Como parte del proceso podemos ver que cuando la suma de los dígitos correspondientes es mayor que 10, entonces tomaremos solo el último dígito resultante, y activamos una “bandera” (señal, variable) de que “llevamos” 1. Ejemplo 9 + 5 = 14, tomamos el 4 y lo escribimos como resultado pero… “llevamos” 1, éste número que “llevamos” (o que “acarreamos”) lo sumaremos con el digito siguiente en la suma (ver imagen 2).

El ejercicio se trata entonces, de ejecutar la serie de pasos anterior tantas veces como dígitos haya e ir guardando el resultado en una variable de tipo cadena.

Un pseudocódigo de acuerdo a lo que podemos ver en las imágenes sería algo como esto (click en la imagen para ver más grande):



Al pseudocódigo anterior le hace falta algo… ¿qué pasa si al sumar los dígitos más significativos resulta que tenemos un número mayor que 10?, ¿Cómo nos damos cuenta o qué condición le ponemos al programa para decirle que en ese caso sí escriba el número completo a la cadena de resultado?. Se me ocurren dos soluciones, una involucra poner un IF y su condición, y la otra es más sencilla…. se trata simplemente de añadir un 0 al inicio de cada cadena una vez que ambas son de la misma longitud (esto se haría en el lugar donde está el “COMENTARIO XYZ”). De esa manera, el acarreo podrá llevarse a cabo si lo hubiera y se sumaría Acarreo + 0 + 0 = Acarreo que sería igual a 1.

A Continuación pueden ver el código en VB.NET. En el código los números no son de 300 dígitos, sin embargo los invito a escribir 200 dígitos o más y probar el algoritmo.



Sub Main()
Dim S1, S2 As String
Dim L1, L2 As Integer
Dim Carry As Byte
Dim Resultado As String = ""

S1 = "98234187364192784619278461923487619237846"
S2 = "2837498749284798791872310928370139812"

L1 = S1.Length
L2 = S2.Length

If L1 <> L2 Then
If L1 > L2 Then
S2 = (New String("0"c, L1 - L2)) + S2
Else
S1 = (New String("0"c, L2 - L1)) + S1
End If
End If

S1 = "0" + S1
S2 = "0" + S2
Carry = 0

Dim D1, D2, D3 As Integer
Dim R1 As String = ""
For i As Integer = S1.Length - 1 To 0 Step -1
D1 = Byte.Parse(S1.Chars(i))
D2 = Byte.Parse(S2.Chars(i))
D3 = Carry + D1 + D2

If D3 >= 10 Then
D3 = D3 - 10
Carry = 1
End If

R1 = D3.ToString
Resultado = R1 + Resultado
Next

MsgBox("El resultado es: " + Resultado)

End Sub



El código presentado aquí puede ser refinado muchísimas veces de manera que sea más eficiente y tenga mejor rendimiento y por lo tanto, consuma menos recursos o ejecute en un tiempo menor. En primer lugar podríamos (y deberíamos) utilizar Arrays en lugar de Strings pero eso ya les queda a ustedes de tarea. Sin embargo, este un buen comienzo y se pone en práctica la lógica de programación. Lo que quería dejarles en este artículo es indicarles que no deben verse limitados por las capacidades de los tipos de datos, siempre hay trucos que se pueden realizar para obtener lo que necesitamos.

viernes, 8 de agosto de 2008

La importancia de la lógica de Programación

¿Qué separa a un buen programador de uno “normal”?. Yo diría que la lógica de programación. El lenguaje de programación (su sintaxis) es algo que encontrarás en muchos libros o en los manuales de ayuda de la aplicación, pero ¿como es que teniendo los mismos libros para aprender, una persona realiza mejores programas que otra?.

El conocer un lenguaje de programación, su sintaxis, librerías y pormenores tiene su mérito y sobre todo, su nicho de mercado. Sin embargo, más importante que eso cuando se sale a conseguir trabajo ya sea como empleado o como “freelance” es tener lógica de programación.

A lo largo de mi carrera profesional, he aprendido a utilizar varios lenguajes de programación tales como C++, Delphi, C++ Builder, ASP, VB6, VB.NET, ASP.NET, PHP, JSP, JavaScript. ¿Y qué tienen todos ellos en común?, pues que siempre existe una manera de tomar decisiones, realizar repeticiones, declarar funciones o procedimientos, declarar variables. Es cierto que en cada uno se escriben de manera diferente.

¿Cuánto te puedes tardar en conocer (y digo conocer más no dominar) un lenguaje de programación?. Aproximadamente 15 días. ¡Claro que no será así la primera vez!. Cuando comencé a estudiar Turbo Pascal por allá de 1996 durante la preparatoria, me tomó mucho más que eso ‘agarrarle la onda’ a esto de la programada. Tuve que realizar muchísimos ejercicios y pruebas para poder comprender la lógica de programación. Sin embargo, una vez dominada la lógica aprender un nuevo lenguaje es más sencillo cada vez.

Todos hemos escuchado esa frase que dice: “al que más tiene más se le dará, y al que tiene menos, aún eso poco que tiene se le quitará”, la cual aplica también al conocimiento. Un ejemplo más claro: “use it or loose it”, “lo que no se usa se oxida”. Y esto aplica también al conocimiento. Veamos… el cerebro es una “máquina” de aprender, y mientras más aprenda más conexiones realiza entre sus neuronas, y mientras más conexiones tenga, más poder de asociación tendrá y más sencillo le resultará aprender.

Ok, ok, me desvié un poco, ¿cuál es el punto?. El punto es que mientras más lógica de programación tengas y más lenguajes de programación conozcas, más fácil te será aprender un nuevo lenguaje de programación ya que los conceptos son muy parecidos entre ellos, de hecho, si conoces C++ se puede decir que ya conoces una parte de Java ó de PHP. Y si conoces Turbo Pascal, ya conoces una parte de Delphi y por lo tanto se te facilitará aprender otro lenguaje de la misma especie como Visual Basic .NET y se te facilitará luego conocer ASP.NET . Revisa la gráfica que aparece a continuación y observa como el conocimiento de un lenguaje te facilita otro.


Sin embargo, el hecho de conocer varios lenguajes de programación no te hace mejor programador porque podría ser que ¡seas malo en todos!, o por otro lado, tal vez conoces unos pocos y eres bueno programando y cuando estudias otro lenguaje de programación ¡también eres bueno en ese!.

Tampoco olvidemos que cada lenguaje de programación tiene su ámbito (de esto hablaremos en otro post en un futuro cercano), esto es, su lugar de aplicación, no puedes intentar programar una aplicación de base de datos utilizando solamente lenguaje ensamblador, de la misma forma, no intentes programar el control remoto de la televisión utilizando Visual Basic .Net

Ok, ok…. Me desvié de nuevo del tema del post, ¿cuál es la importancia de la lógica de programación?. La importancia de la lógica es que programar no es como tener una receta, no es una lista de pasos a seguir, aunque muchos quieran verlo de esa manera, no se puede aplicar la misma solución en todas las ocasiones y lo más importante de programar aplicaciones del tipo que sea es que tengas la capacidad de adaptarte a los requerimientos del entorno. La buena noticia es que la lógica de programación es algo que se desarrolla, la mala... es que se desarrolla practicando y realizando ejercicios.

Hola Mundo !!

Hola Mundo.

Aquellos que se dediquen al mundo de la programación ya comprenderán el porqué del título de este post. En este blog escribiré cosas de programación en diversos lenguajes de programación y en diferentes niveles de dificultad. Básicamente son:
• mini-tutoriales que iré escribiendo conforme mis conocidos me pregunten de situaciones de programación.
• temas que me han llamado la atención al estar resolviendo un problema o incluso solamente navegando.
• Tutoriales en varios fascículos de algún tema interesante de cualquier nivel de dificultad.
• Respuestas a preguntas interesantes que me planteen en este blog.

Espero que la información que puedas encontrar sea amena y sobre todo, útil. Si tienes algún tema que te gustaría tratar, favor de anotarlo en el post.

¡Saludos!