Zeller congruence in 176 bytes

published: 12 December 2020 / updated 12 December 2020

Lire cette page en français

 


Zeller congruence

These formulas are based on the observation that the day of the week progresses in a predictable manner based upon each subpart of that date. Each term within the formula is used to calculate the offset needed to obtain the correct day of the week.

The formula for the Julian calendar:

The formula for the Gregorian calendar. It is this formula which will be processed in FORTH language:

where:

January and February are counted as month 13 and 14 of the previous year.

The formula for gForth

\ Zeller's Congruence
: zeller ( m -- days since March 1 )
    9 + 12 mod 1-   
    26 10 */ 3 +
  ; 
: weekday ( d m y -- 0..6 )   \ Monday..Sunday
    over 3 < if 1- then
    dup    4 /
    over 100 / -
    over 400 / +  +
    swap zeller + +
    1+ 7 mod
  ;

With gForth, the compilation of this formula will occupy 240 bytes in the Forth dictionary.

To test the formula, all you have to do is precede the word weekday with numbers of the day, month and year. Example:

12 12 2020 weekday
\ display 5

The order of the parameters is: day month year.

The days are numbered from 0 to 6, the week starting with Monday and ending with Sunday.

The value 5 therefore indicates Saturday.

The formula for FlashForth

It is exactly the same as for gForth, but you must first compile these definitions that will complete the FlashForth arithmetic function set:

: m*  ( n1 n2 -- d )
    2dup xor >r
    abs swap abs um*
    r> ?dnegate
  ;
: sm/rem ( d1 n1 -- n2 n3 )
    2dup xor >r over >r
    abs >r dabs r> um/mod
    swap r> ?negate
    swap r> ?negate
  ;
: /mod ( n1 n2 -- n3 n4 )
    >r s>d r> sm/rem
;
: mod ( n1 n2 -- n3 )
    /mod drop
  ;
: */ ( n1 n2 n3 -- n4 )
    >r m* r> sm/rem nip
  ;

On FlashForth, the formula contained in the words zeller and weekday occupies only 176 bytes. This difference is explained by the fact that gForth manages the data and 32-bit execution codes, compared to 16 bits for FlashForth.

Day of the week decoding

For gForth:

: str-table ( comp: n -- | exec: n -- str len)
    create
        0 do
            ,
        loop
    does>
        swap cells + @ count
  ;
here ," Sunday"
here ," Saturday"
here ," Friday"
here ," Thursday"
here ," Wednesday"
here ," Tuesday"
here ," Monday"
7 str-table weekdays

Example of use:

12 12 2020 weekday weekdays type
\ display Saturday

For FlashForth:

\ get real addr2 and u length form addr1
: count ( addr1 --- addr2 u)
    dup c@          \ push real length
    swap 1+ swap    \ push start address of datas
  ;
: str-table ( comp: n -- | exec: n -- str len)
    create
        for
            ,
        next
    does>
        swap cells + @ count
  ;
flash
here ," Sunday"
here ," Saturday"
here ," Friday"
here ," Thursday"
here ," Wednesday"
here ," Tuesday"
here ," Monday"
7 str-table weekdays
ram

Good programming...