Sull'informatica: si fa presto a dire bisestile

L'informatica spesso si scontra con la risoluzione di problemi reali in un modo più simile alla fisica che non alla matematica. In matematica, l'aspetto astratto consente di rifuggere dalle pochezze della realtà. La fisica e l'informatica invece devono dare risposte concrete a problemi reali. Oltre a ciò l'aspetto ingegneristico della informatica la costringe a fare più spesso i conti con la pochezza delle risorse contingenti, cose che un fisico ogni tanto deve fare, spesso può evitare con i modelli astratti.

La gestione del calendario perpetuo è una di queste realtà complesse, almeno a giudicare da cosa successe ad un famoso foglio elettronico negli anni 80...


 

A prima vista può sembrare semplice gestire un calendario perpetuo di tipo occidentale: imparata la filastrocca per l'ultimo giorno del mese (trenta giorni a novembre con aprile, giugno e settembre, di ventotto ce ne uno, tutti gli altri fan...) l'ultimo problema è trovare quando l'anno è bisestile.

Il calendario occidentale è chiamato Calendario Gregoriano, perché papa Grerogio nel 1582 si accorse che il calendario Giuliano (inventato da Giulio Cesare circa 1540 anni prima) era come dire...sbiellato da far paura (termie tecnico).

Leggiamo da Wikipedia

Secondo il calendario giuliano, sono bisestili gli anni la cui numerazione è multipla di 4: l'anno giuliano medio dura quindi 365 giorni e 6 ore (la media di tre anni di 365 giorni e uno di 366). Questa durata non corrisponde esattamente a quella dell'anno solare medio, che si ricava dalle osservazioni astronomiche: quest'ultimo infatti è più corto di 11 minuti e 14 secondi. Di conseguenza, il calendario giuliano accumula un giorno di ritardo ogni circa 128 anni rispetto al trascorrere delle stagioni.

La questione della progressiva regressione dell'equinozio di primavera dovuta all'imprecisione del calendario giuliano era nota e dibattuta fin dal concilio di Nicea (325)

Tra il 325, anno in cui il Concilio di Nicea stabilì la regola per il calcolo della Pasqua, e il 1582 si era ormai accumulata una differenza di circa 10 giorni. Questo significava, ad esempio, che la primavera, in base alle osservazioni astronomiche, non risultava più cominciare il 21 marzo, ma l'11 marzo. Così la Pasqua, che sarebbe dovuta cadere la prima domenica dopo il plenilunio di primavera, veniva spesso a cadere nella data sbagliata.

Nota personale: per un cristiano oltranzista del 1500 l'impossibilità di festeggiare la Pasqua nel giorno corretto  poteva essere abbstanza grave da richiedere l'intervento della Santa Inquisizione, per cui la cosa era abbastanza seria.

Si noti come l'errore sia subdolo: si era riscito a scoprirlo ma non ne era chiara la ragione! Si trattava di un "bug" nel sistema di calcolo del calendario, che rimase irrisolto per ben 1500 anni.

Era già di dominio pubblico nel medioevo, tanto che ne parla Dante nella divina commedia (e quindi intorno al 1300)...

« Ma prima che gennaio tutto si sverni per la centesma ch'è là giù negletta »
(Paradiso XXVII, 142-143)

Ora questo è un problema noto, e già risolto a fine del 1500... nonostante questo, come è possibile  dei furbacchioni durante lo sviluppo di Lotus1-2-3 decisero che il 1900 dovesse diventare un anno bisestile....?

"So, it's a bug in Lotus 123?"

"Yeah, but probably an intentional one. Lotus had to fit in 640K. That's not a lot of memory. If you ignore 1900, you can figure out if a given year is a leap year just by looking to see if the rightmost two bits are zero. That's really fast and easy. The Lotus guys probably figured it didn't matter to be wrong for those two months way in the past. [.....]"

(colloquio tra Joel Sposky e Ed Fries).

Il problema qui è semplice: calcolare correttamente un anno bisestile non è banale, e per tutti gli anni '80 la potenza dei personal computer era limitata dall'ammontare di memoria che un povero derelitto poteva permettersi a casa. Per cui la funzione "semplice"  isLeapYear() si poteva fare confrontando solo se l'anno era divisibile per quattro con una base precisa (una manciata di istruzioni macchina) mentre la formula esatta per l'anno bisestile è qualcosa del tipo

  1. If the year is evenly divisible by 4, go to step 2. Otherwise, go to step 5.
  2. If the year is evenly divisible by 100, go to step 3. Otherwise, go to step 4.
  3. If the year is evenly divisible by 400, go to step 4. Otherwise, go to step 5.
  4. The year is a leap year (it has 366 days).
  5. The year is not a leap year (it has 365 days).

da http://support2.microsoft.com/kb/214019

O anche (in EXCEL):

=IF(OR(MOD(A1,400)=0,AND(MOD(A1,4)=0,MOD(A1,100)<>0)),"Leap Year", "NOT a Leap Year")

In altri termini la terra completa un giro intorno al sole in 365,242375 giorni, e l'algoritmo dato è una buona approssimazione di questo rapporto.

Ora, questa funzione occupa una manciata di bytes in più di quella di bitshift, quindi questo spiega a che punto di ristrettezze fosse il team di Lotus1-2-3 (oppure rivela una profonda ignoranza della storia del calendario Gregoriano... a voi la scelta :)