This program factorises integers up to 4,294,967,296 (2³²) by trial division, using a compact wheel-factorisation scheme stored in DATA statements. Rather than testing every integer as a divisor, it uses a precomputed sequence of 48 increments that skips multiples of 2, 3, 5, and 7, reducing the number of trial divisions significantly. A notable challenge addressed in the code is that the machine’s floating-point arithmetic cannot represent large integers exactly, so lines 300–320 implement a custom large-number printing routine that splits the number at 100,000 to avoid precision loss. The loop at line 130 uses a `RESTORE`/`NEXT B` trick to cycle through the wheel increments repeatedly without a conventional loop restart.
Program Analysis
Program Structure
The program is organised into three logical sections:
- Initialisation (lines 20–60): DATA tables are defined and the user inputs a number
N. - Factorisation loop (lines 70–130): Trial division using a wheel increment sequence read from DATA.
- Output and large-number printing (lines 200–320): Handles prime reporting and a subroutine for printing numbers that exceed floating-point integer precision.
Wheel Factorisation
The DATA at lines 20 and 30 encode a wheel — a sequence of 53 increments (starting from 2) that, when accumulated, generate candidate divisors coprime to 2, 3, 5, and 7. This avoids testing any multiple of those primes, giving roughly a 77% reduction in trial divisions compared to testing every integer. Line 20 seeds the first few small primes (2, 3, 5, 7, 11) and line 30 provides the 48-step repeating cycle of the wheel.
The loop at lines 80–130 reads each increment Z from DATA, accumulates into D, and tests whether D divides N exactly. When the wheel is exhausted (after 53 steps, B runs 0 to 52), line 130 executes RESTORE 30 to reset to the repeating part of the wheel, then sets B=4 before NEXT B increments it to 5, effectively re-entering the FOR loop mid-cycle to continue with the 48-step repeat. This is a well-known BASIC trick for cycling through DATA without a full restart.
Termination Condition
The trial division stops early at line 100 when Q = N/D is less than D. At that point, any remaining factor of N must be prime (it cannot have two factors both greater than its square root), so the remaining N is printed directly by the subroutine at line 300.
Large-Number Printing Subroutine (Lines 300–320)
The ZX81/TS1000/Spectrum floating-point format holds only about 9–10 significant decimal digits, so numbers approaching 2³² ≈ 4.3 × 10⁹ can be printed in scientific notation rather than as exact integers. The subroutine at line 300 works around this:
H = INT(N / 1e5)extracts the high part (digits above 100,000).- If
His zero, the number fits in five digits and is printed directly. - Otherwise,
His printed, thenSTR$(N - 1e5*(H-1))produces a string of the form"1XXXXX"(always six characters starting with 1 due to theH-1offset), and(2 TO )slices off the leading"1", yielding the zero-padded lower five digits.
This is an elegant two-part decimal split that avoids any reliance on integer formatting and correctly zero-pads the lower segment.
Output Formatting
Line 110 uses the expression PRINT "=" AND NOT F to conditionally print the equals sign only before the first factor — when F=0 (no factor found yet), NOT F is 1, so "=" AND 1 yields "="; subsequently NOT F is 0 and the string evaluates to "". This avoids an explicit IF branch for the separator, keeping the line compact.
Key Variables
| Variable | Role |
|---|---|
N | Current number being factorised (reduced as factors are found) |
D | Current trial divisor (accumulated from wheel increments) |
Z | Wheel increment read from DATA |
B | FOR loop counter (0–52) over the DATA entries |
F | Flag: 0 if no factor found yet, 1 after first factor |
Q | Quotient N/D, tested for integer value |
H | High part of N in the printing subroutine |
Notable Anomalies
The RESTORE 30: LET B=4: NEXT B at line 130 re-enters the FOR B=0 TO 52 loop by manipulating the loop counter directly. This relies on the interpreter allowing NEXT B to continue a loop whose counter was set outside of it, which is standard behaviour. However, because B is set to 4 and then NEXT B increments it to 5, the loop will now run from 5 to 52 — consuming 48 iterations, matching the 48 entries in the DATA at line 30 exactly.
The upper limit stated in the prompt (<=4294967296) is 2³², but the actual reliable limit is constrained by floating-point precision to numbers where all factors can be distinguished exactly — in practice the routine works correctly for inputs within the ~9-digit precision range of the floating-point system.
Content
Source Code
1 REM "FACTORISE"
2 REM By W.E. Thomson
3 REM ZX Computing Monthly
20 DATA 2,1,2,2,4
30 DATA 2,4,2,4,6,2,6,4,2,4,6,6,2,6,4,2,6,4,6,8,4,2,4,2,4,8,6,4,6,2,4,6,2,6,6,4,2,4,6,2,6,4,2,6,4,10,2,10
40 RESTORE 20
50 INPUT "INPUT A NUMBER <=4294967296: ";N
60 GO SUB 300
70 LET F=0: LET D=0
80 FOR B=0 TO 52: READ Z: LET D=D+Z
100 LET Q=N/D: IF Q<D THEN GO TO 200
110 IF Q=INT Q THEN PRINT "=" AND NOT F;D;"*";: LET F=1: LET N=Q: GO TO 100
120 NEXT B
130 RESTORE 30: LET B=4: NEXT B
200 IF NOT F THEN PRINT " IS PRIME";
210 IF F THEN GO SUB 300
220 PRINT : GO TO 40
300 LET H=INT (N/1e5)
310 IF NOT H THEN PRINT N;: RETURN
320 PRINT H;(STR$ (N-1e5*(H-1)))(2 TO );: RETURN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
