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:
- Title screen and intro text (lines 10–180)
- Year input and range validation (lines 190–380)
- Easter date calculation (lines 390–550)
- Result display (lines 560–790)
- 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:
| Variable | Meaning |
|---|---|
N | Year offset from 1900 |
A | Year’s position in the 19-year Metonic cycle |
B | Epact correction term |
M | Paschal full moon day offset |
Q | Leap-year quarter correction |
W | Day-of-week offset |
DE | Final 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 withVAL(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.00001instead of4to prevent floating-point precision errors from causingMto 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 setsM = 0) and then falls through to line 510 (the body that would have been reached viaGO SUB 510). IfX ≠ 1,Mis assigned at line 480 and thenGO SUB 510is called at line 490 — but the subroutine at 510 has noRETURN, meaning this behaves as aGO 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 510at line 490 is never matched by aRETURN; execution simply falls through. If the subroutine were ever truly called (with a return address on the stack), aRETURNerror 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 aPAUSE 200, only uppercaseYwill loop, even though lowercaseywas allowed by the first condition. - Line 500 reachable by fall-through and by jump: After the
GO TO 500at line 470 setsM = 0, execution continues at line 510 — which is correct. However, in theX ≠ 1branch,GO SUB 510at line 490 also continues at line 510, soMassigned 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.
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.

