Friday, August 08, 2008

Miles de años en la cabeza

En memoria de mi papá

Programar es siempre una labor fascinante, aunque no carente de dificultades, amargura ocasional y sentimientos de frustración. Más de una vez nos hemos topamos con problemas difíciles de codificar, o bien, demasiado ineficientes como para no buscar una mejor solución.

Uno de esos problemas me ocurrió hace algunos meses. Debido a un proyecto particular de software, tenía que escribir un algoritmo que me desplegara en pantalla el calendario de cualquier mes y cualquier año. Esta tarea la tomé con verdadero agrado porque he visto multitud de paquetes y programas que hacen algo muy similar (por ejemplo el antiguo Sidekick [Borland - ahora Embarcadero] o cualquier agenda Casio). Da cierto sentimiento de seguridad saber que alguien más ya logró el algoritmo buscado, por lo que suponemos -confiadamente muchas veces- que si ya está escrito, debe ser relativamente sencillo re-escribirlo.

Así entonces empecé por discurrir cuáles son los requerimientos para escribir un algoritmo -que despliegue en pantalla- el calendario de cualquier mes y cualquier año. En primera instancia, se necesita saber en qué día cayó el primer día del mes del año en cuestión a desplegar. Teniendo este dato, lo siguiente es comenzar a desplegar en pantalla en la posición correcta (es decir, bajo la columna que el día que le corresponde) el día uno, día dos, día tres, etc. Evidentemente hay que tomar en cuenta si el año es bisiesto, amén de considerar la cantidad de días que tiene el mes a presentar.

Hallar en que día cae el primer día de cualquier mes en cualquier año se puede hacer utilizando casi cualquier lenguaje de programación, que ya tiene todas esas rutinas implantadas. Sin embargo, utilizar este método tiene un inconveniente, el cual es que convertimos a nuestro algoritmo dependiente de la plataforma en la que está siendo desarrollado. Es decir, en otras palabras, que si me cambio a otra plataforma (por ejemplo una Mac), seguramente la función que controla la fecha se llama de otra manera, lo cual equivale a tener que reescribir todo el código. Quizás no es un gran problema, pero demostraría una vez más que la portabilidad de código entre plataformas es un mito.

¿Qué hacer entonces? Pues recordé que de niño mi hermano Pedro podía hacer este cálculo de los días con precisión absoluta y dicho arte lo ponía en práctica en reuniones familiares en donde en ocasiones yo hacía un acto de transmisión de pensamiento con mi papá. (Sí, ya sé que quien lo vio alguna vez dirá que era un buen truco, pero la cuestión es que nunca pudieron averiguar cómo hacíamos. La razón es simple: era un acto verdadero). Pedro me explicó que la idea del cálculo era de nuestro padre, así que fui a preguntarle y descubrí una historia fascinante. Cuando mi papá era niño trabajó en algún momento en un circo (con sus hermanos, en un conjunto que hacía llamarse “los hermanitos López”). Ahí había un ilusionista que hacía este truco a una audiencia que se quedaba atónita con la precisión de los resultados. Aunque mi papá le preguntó al mago en cuestión cómo le hacía, éste nunca quiso decirle nada (un mago jamás revela sus trucos, supongo). Por ello, en una especie de obsesión, mi padre trabajó sobre el problema y logró algo notable: encontró su propio algoritmo para saber en qué día caía cada día de cada año. Sorprendente y notable, porque mi padre no tenía preparación matemática. Este mismo algoritmo lo hallo Pascal, ni más ni menos.

Pero bueno, de pronto recordé haber leído alguna vez en un libro de magia, un método para calcular el día que corresponde a cualquier mes y año. La obra de marras se denomina: Enciclopedia de la Magia, Ilusionismo y Prestidigitación, por Antonio de Armenteras, De Gasso Hermanos (editores), tercera edición, 1959, del cual transcribo el algoritmo, además de alguno que otro pasaje de interés.

El capítulo del mágico libro se llama "Miles de Años en la Cabeza" y comienza así:

"El artista solicita del público que le pregunte que día de la semana corresponde a una fecha para él señalada: nacimiento, término de carrera, boda, etc.; la que sea. A los pocos segundos de hecha la pregunta responderá consignando que el día consultado era lunes, o martes, o miércoles, etc."

El mismo libro da fe que quien explicó dicho algoritmo fue el ilustre Presidente de la Sociedad Española de Ilusionismo, Don Javier Areny Plandolit, aunque no aclara si este personaje es quien inventó este método de cálculo. En cualquier caso, el procedimiento va como sigue:

Dicho sistema consiste en asignar un número a cada uno de los doce meses del año, con arreglo a la siguiente relación:

mayo 1
agosto 2
febrero, marzo y noviembre 3
junio 4
septiembre y diciembre 5
abril y julio 6
enero y octubre 0

Así mismo, es preciso numerar los días de la semana de la siguiente manera:

domingo 1
lunes 2
martes 3
miércoles 4
jueves 5
viernes 6
sábado 0


Acto seguido, se procede hacer la siguiente suma, cuyos sumandos serán:

(1) el día escogido por el espectador
(2) el número formado por las dos últimas cifras del año elegido
(3) la cuarta parte entera del número anterior
(4) tres unidades, si el año es anterior a 1900, y una unidad si el año es el 1900 o posterior a éste
(5) el número que corresponde al mes, en la tabla anterior publicada

La suma de esa manera obtenida, se divide por 7, y el residuo de esa división, será el número que indique el día de la semana, según la tabla dada anteriormente.

Un detalle más: cuando el año que se interese sea bisiesto, entonces habrá que sustraer una unidad del residuo, pero únicamente cuando los meses solicitados sean enero o febrero. Ingenioso sin duda, pero ¿funcionará? Intentemos algo simple de verificar: ¿Qué día de la semana fue el 1 de enero de 1992?

(1) día escogido 1
(2) dos últimas cifras de 1992 92
(3) cuarta parte entera de 92 23
(4) un 1 por tratarse del año posterior a 1900 01
(5) número del mes de diciembre en la tabla 00

Total 117

Dividiendo 117 entre 7, da 5 de residuo. Pero cuidado, 1992 es bisiesto, y el mes cuestionado es enero, por lo que al residuo hay que restarle un uno. En consecuencia, según la tabla de días, el 4 corresponde al miércoles, lo cual es correcto.

Las virtudes de este algoritmo son evidentes: es independiente del lenguaje y máquina en el cual se codifica y es muy simple de implementar. Quizás lo más difícil en todo caso, sea explicar cómo funciona, o más bien, por qué trabaja correctamente este procedimiento. No lo voy a hacer aquí y se le deja de tarea al lector curioso. Baste decir que el algoritmo en cuestión es -para aquellos con cierta preparación matemática- una función periódica que va de cada punto del dominio (cada número de día de cada mes) a un solo punto en el codominio (uno y sólo un día de la semana, aunque la función no es evidentemente biyectiva). O bien, piénsese en el concepto de “módulo”, el cual en este caso es siete. Por ahí anda la solución. Sin embargo, más sorprendente es para mí, el inextinguible ingenio humano el cual en ocasiones, es como verdadera magia.

3 comments:

Yixus said...

Qué buen post. Y curiosa la casualidad de que lo publiques ahora. Justo en la oficina hace unos días estuve pensando cómo se podría hacer esto para una aplicación que estamos haciendo. Aunque por el momento ya lo solucionamos usando un calendario ya hecho, pero habrá que adaptarse a él.

Marga said...

Buen post hermano, papá era sorprendente! un verdadero mago de la intuición.

beso!
M

yano2h said...

Muy bueno me sirvio mucho
pero creo que le falta algo ya que cuando lo use, me fallaron los año del 2000 en adelante, asi que revisando los valores que me daban con los que me deberian dar ,me di cuente que en la parte que dice:
(4) tres unidades, si el año es anterior a 1900, y una unidad si el año es el 1900 o posterior a éste,
la cambias por esta que se me ocurrio:
(4) 3 si año<1900, 1 si 1900<=año<2000 y 0 si año>=2000

con es modificacion me funciono bien,asi que para que revises la fuente original para ver si no te falto algo, espero que les sirva.

saludos y gracias