top of page

Matemáticas básicas: La importancia de la función parte entera

  • fjroar
  • 15 dic 2024
  • 5 Min. de lectura

Aprovechando que estoy investigando algoritmos que tienen que ver con la Luna, me encuentro con uno en particular, muy sencillo y que es la base de la mayoría de los algoritmos astronómicos como es el cálculo del día juliano.


Aunque no me voy a poner describir este algoritmo en este momento, lo que me llama la atención es el gran uso que hace de una función que se enseña en lo que ahora es segundo o tercero de la ESO (o al menos eso creo y espero) y antes era séptimo u octavo y que me parece incluso hasta más interesante que la fórmula de I = Crt/100 que para los preocupados en que se enseñe como pedir créditos a los chavales (véase algún comentario de linkedin anterior que hice), también se enseña por ese tramo de edad.

Pues bien, la gráfica de la función resulta ser la siguiente:


Imagen generada en R con plotly usando la función floor()
Imagen generada en R con plotly usando la función floor()

Así pues, como la mayoría de la gente sabe, por ejemplo, la parte entera de -1.65 es -2 y si se quiere mayor detalle se puede consultar en https://eliatron.blogspot.com/2012/05/cuanto-vale-la-parte-entera-de-165.html

Sin embargo, el problema que se tiene en Astronomía es que el grado de precisión importa y por ejemplo, si hago la pregunta de ¿Cuál es la parte entera de -2.001? Estoy seguro que casi todo el mundo acierta y me dice -3, de hecho, si en R hago eso, observo lo mismo con tan sólo teclear lo siguiente:

                                                           floor(-2.001)


O al que le guste Python (que también los hay y tendrán que llamar a una librería):


                                                           import math

math.floor(-2.01)

 

Sin embargo ¿Cuál sería el resultado de lo anterior con:


                                                           floor(-2.0000000000000001)

O con:

                                           import math

math.floor(-2.0000000000000001)

 

La respuesta sorprendente, al menos en mi máquina de de 64bit, hp de 32gb de ram es que el resultado es -2 y sólo hay 16 decimales tras la coma, lo cual en algoritmos de alta precisión os podéis imaginar qué sucede.


Lo anterior, me obligó en la función que tengo par el cálculo de días julianos en mi librería RMoon y que podéis encontrar en https://github.com/FJROAR/RMoon/blob/main/R/JulianDayMeeus.R  a definir una función especial (por recomendación del libro de Jean Meeus y del responsable del Grupo de Observación Lunar de la Agrupación Astronómica de Madrid https://www.aam.org.es/, el gran Alberto Martos a programar algo específico para evitar errores que diese problemas en el cálculo del día juliano y por tanto para ser preciso en el algoritmo encontráis la función goodInteger():

   

goodInteger <- function(number){

for (i in c(1: length(number))){

  number[i] <- ifelse(number[i] < 0, as.integer(number[i]) - 1, as.integer(number[i]))

}


return(number)


}

 

Que soluciona este problema y ofrece el valor correcto pero ¿Por qué es tan importante calcular bien la función parte entera de un número? Pues bien, en el algoritmo del cálculo del día juliano, cuyo concepto parte de Justus Scaliger (1540 – 1609) en 1583, existen algunas piezas claves, (y que incorporo en RMoon) siendo una de las importantes la siguiente:

 

JD <- goodInteger(365.25 (Y + 4716)) + goodInteger(30.6001 (M + 1)) + D + B - 1524.5

 

No voy a hablar del algoritmo en sí y de todo lo que significa la anterior línea, pero sí me voy a detener en el primer sumando y en la última resta, es decir, en el último número que se descompone como 1524.5 = 1461 + 62 + 1.5. Esta línea se puede re-escribir del siguiente modo para separar los efectos en 2 partes distintas:

 

JD1 <- goodInteger(365.25 * (Y + 4716)) – (1461 + 1.5)

JD2 <- goodInteger(30.6001 *(M + 1)) + D + B – 62

 

Fijémonos en JD1, ya que JD2 sirve para otros temas que tienen que ver con la reforma de Gregorio XIII de 1582.


Partiendo de la base de que Y es un año cualquiera. ¿Qué sucede cuando por ejemplo es el año 2022? Pues en ese caso el valor que toma JD1 sería:


[365.25 * (2022+4716)] – 1462.5 = [2461054.5] – 1462.5 = 2461054 – 1462.5 = 2459591.5


Es decir, al no ser 2022 bisiesto el decimal 0.5 no tiene efecto y se anula y no se cuenta y se acaban contando 365 días que se resta a una cantidad fija, pero es que si se considera por ejemplo el año 2023, el resultado sería:


[365.25 * (2023+4716)] – 1462.5 = [2461419.75] – 1462.5 = 2460689 – 1462.5 = 2459956.5


Y ahora, que el redondeo natural sería una cifra más por ser 0.75 lo que hay dentro de la función parte entera, también desaparece y se sigue contando esos 365 día, pero fijémonos que cuando se alcanza el año 2024, sucede lo siguiente:


[365.25 * (2024+4716)] – 1462.5 = [2461785] – 1462.5 = 2461785 – 1462.5 = 2460322.5


¡Ahora no se eliminan decimales! Porque cada 4 años, la parte 0.25 de 365.25 aumenta un día y ese día se mantiene inalterado mientras que, en el resto de los casos, ese 0.25 no tiene efecto y así con una simple línea donde la función parte entera es esencial se van contando los años (¡Ojo! Que como he mencionado hay más cosas en el algoritmo pero quería mostrar la ingeniosidad de la esta función).


Además, se puede comprobar que como no podía ser de otro modo que la diferencia de días entre los años se mantendría del siguiente modo:


                                             2460322.5 – 2459956.5 = 366

                                             2459956.5 – 2459336.5 = 365


Por tanto la función parte entera es muy útil para la configuración de modo eficiente e ingeniosa de algoritmos como el aquí presentado, pero que nos advierte de que hay que tener cuidado con las funciones que vienen de los lenguajes a nivel base o en librerías estándar y que todo el mundo asume que hace bien los cálculos pero que no alcanza el grado de exactitud que se requiere sobre todo en los puntos límite y vuelvo a recordar que en la época actual con el hype de la Inteligencia Artificial donde las funciones ReLu que componen muchos de nuestros algoritmos y que usan funciones similares a la parte entera.


Miedo me da, cuando hay miles de estas funciones entremezcladas donde no se ha hecho un estudio adecuado de si en casos límite, la cosa va o no, después vienen las “alucinaciones”, los errores de predicción inexplicables, … pero si fallamos en la base, después es difícil encontrar por qué todo fue mal.


Finalmente quisiera acabar con que hay que investigar y aprender y esto no va sólo apostar y arriesgar patrimonios y si no lo haces eres un looser, admiro a quien lo hace, pero también admiro al que estudia e indaga y no se queda con la primera respuesta, le da vueltas a las cosas y también se equivoca, este último es muy posible que no llegue a ser millonario, pero tiene altas probabilidades de disfrutar con lo que hace, e investigar el día juliano te lleva a analizar cómo funciona el tiempo, los calendarios, cómo se establece la hora civil, … y eso te llena el alma, aunque no la cuenta bancaria.

Comments


© 2021 by Francisco J. Rodríguez Aragón. Proudly created with Wix.com

bottom of page