Easter

Developer(s): Louis LaFerriere
Date: 198x
Type: Program
Platform(s): TS 2068
Tags: Calendar

This program calculates the date of Easter Sunday for any year between 1900 and 2099 using an algorithmic approach based on modular arithmetic. The core algorithm derives the Easter date through several intermediate variables—including a Metonic cycle value (A), an epact correction (B), and day-of-week offsets (Q, W)—before arriving at a day number relative to April 25. The program includes hard-coded corrections for 1974, 1984, and 1994 to patch known discrepancies in the algorithm. Input is accepted as a string via INPUT Y$ then converted with VAL, and a simple range check enforces the 1900–2099 boundary. The program loops to allow multiple year lookups within a single session.


Program Structure

The program is organized into a linear flow with a few branching subroutines. An introductory display at lines 20–180 is followed by the main input-validation-calculation-output loop running from line 190 onward. Line 9000 contains a SAVE with autostart. The major phases are:

  1. Title screen and intro text (lines 10–180)
  2. Year input and range validation (lines 190–380)
  3. Easter date calculation (lines 390–550)
  4. Result display (lines 560–790)
  5. Repeat or quit prompt (lines 830–890)

The Easter Algorithm

The algorithm is a variant of an anonymous Gregorian Easter calculation that was commonly circulated in computing magazines. It uses the following intermediate values:

VariableMeaning
NYear offset from 1900
AYear’s position in the 19-year Metonic cycle
BEpact correction term
MPaschal full moon day offset
QLeap-year quarter correction
WDay-of-week offset
DEFinal day offset from April 25 (negative = March)

The fractional-part trick is central to the algorithm: for example, A = 19*(A - INT(A)) extracts the remainder of N/19 without using MOD, since ZX81 BASIC lacks a modulo operator. The same technique is applied to compute W.

Notable Techniques and Idioms

  • String input for numbers: Year is read as Y$ and converted with VAL(Y$) at line 250, a common idiom to avoid direct numeric INPUT issues.
  • Fractional-remainder arithmetic: Modular reduction is performed via X - INT(X) patterns throughout, substituting for the absent MOD function.
  • Floating-point guard: Line 450 uses 4.00001 instead of 4 to prevent floating-point precision errors from causing M to be computed as a value fractionally below an integer.
  • Conditional GOSUB: Lines 470–500 form an unusual branching structure. If X = 1, execution jumps to line 500 (which sets M = 0) and then falls through to line 510 (the body that would have been reached via GO SUB 510). If X ≠ 1, M is assigned at line 480 and then GO SUB 510 is called at line 490 — but the subroutine at 510 has no RETURN, meaning this behaves as a GO TO, not a proper subroutine. This is a latent bug.

Hard-Coded Year Corrections

Lines 740–760 apply manual patches for three specific years where the generic algorithm produces an incorrect result:

  • 1974 and 1984: day value incremented by 7
  • 1994: day incremented by 7 then reduced by 31, and month changed to April

These corrections suggest the base algorithm used here is an approximation that deviates from the full Gregorian Easter computation for certain exceptional years.

Bugs and Anomalies

  • Missing RETURN at line 510: GO SUB 510 at line 490 is never matched by a RETURN; execution simply falls through. If the subroutine were ever truly called (with a return address on the stack), a RETURN error would occur later. In practice the program runs correctly only because the fall-through path works as intended.
  • Repeat-loop condition bug (line 860): The second condition in IF A$="Y" OR A$="Y" is a copy-paste error — both branches test "Y" rather than "Y" and "y". In effect, after a PAUSE 200, only uppercase Y will loop, even though lowercase y was allowed by the first condition.
  • Line 500 reachable by fall-through and by jump: After the GO TO 500 at line 470 sets M = 0, execution continues at line 510 — which is correct. However, in the X ≠ 1 branch, GO SUB 510 at line 490 also continues at line 510, so M assigned at line 480 is retained. The logic is functionally correct despite the structural oddity.
  • Line 550 computes a negative-biased offset: DE = INT(25 - M - W) yields a day measured from April 25. Negative values indicate March dates, requiring the sign-based branching at lines 660–720 to reconstruct the actual calendar date.

Image Gallery

Source Code

   10 REM Received from Louis Laferriere. GFC
   20 PRINT AT 2,5;"EASTER DATES CALCULATOR"'''
   60 PRINT "THIS PROGRAM CALCULATES THE DATEOF 'EASTER SUNDAY' FOR ANY YEAR BETWEEN 1900 AND 2099"
   90 PRINT :PRINT :PRINT :PRINT 
  180 PAUSE 260
  190 CLS 
  200 PRINT :PRINT :PRINT 
  240 PRINT "YEAR REQUIRED ";
  250 INPUT Y$:LET Y= VAL (Y$)
  270 IF Y<1900 OR Y>2099 THEN GO TO 290
  280 GO TO 390
  290 CLS :PRINT :PRINT :PRINT "INVALID ENTRY"
  330 PAUSE 300
  340 CLS 
  380 GO TO 240
  390 PRINT Y
  400 LET N=Y-1900
  410 LET A=N/19
  420 LET A=19*(A- INT (A))
  430 LET B= INT ((7*A+1)/19)
  440 LET M=0
  450 LET M=(11*A+4.00001-B)/29
  460 LET X=M- INT (M)
  470 IF X=1 THEN GO TO 500
  480 IF X <>1 THEN LET M=29*X
  490 GO SUB 510
  500 LET M=0
  510 LET Q= INT (N/4)
  520 LET W=(N+Q+31-M)/7
  530 LET W=7*(W- INT (W))
  540 LET W= INT (W)
  550 LET DE= INT (25-M-W)
  560 CLS 
  570 PRINT :PRINT :PRINT :PRINT 
  620 PRINT "EASTER SUNDAY ";Y;" IS":PRINT :PRINT :PRINT 
  660 IF DE>0 THEN LET M$="APRIL"
  670 IF DE<0 THEN LET M$="MARCH"
  680 IF DE=0 THEN LET M$="MARCH 31"
  690 IF DE=0 THEN GO TO 780
  700 IF DE<-9 THEN LET DE=DE+9
  710 IF DE<-9 THEN GO TO 700
  720 IF DE<0 THEN LET D=31- ABS (DE)
  730 IF DE>0 THEN LET D=DE
  740 IF Y=1974 OR Y=1984 THEN LET D=D+7
  750 IF Y=1994 THEN LET D=D+7-31
  760 IF Y=1994 THEN LET M$="APRIL"
  770 PAUSE 350
  780 PRINT " ";M$;" ";D
  790 PRINT :PRINT :PRINT 
  830 PRINT "WANT ANOTHER YEAR Y/N ?"
  840 INPUT A$:PRINT A$
  860 IF A$="Y" OR A$="y" THEN PAUSE 200:IF A$="Y" OR A$="Y" THEN GO TO 190
  880 IF A$="N" OR A$="n" THEN GO TO 920
  890 PRINT :PRINT "INVALID REPLY":GO TO 830
  920 CLS 
 9000 SAVE "easter.B1" LINE 1

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.