All Euler problems
Project Euler

An Amazing Prime-generating Automaton

Conway's PRIMEGAME is the FRACTRAN program: (17)/(91), (78)/(85), (19)/(51), (23)/(38), (29)/(33), (77)/(29), (95)/(23), (77)/(19), (1)/(17), (11)/(13), (13)/(11), (15)/(2), (1)/(7), (55)/(1) Start...

Source sync Apr 19, 2026
Problem #0308
Level Level 16
Solved By 900
Languages C++, Python
Answer 1539669807660924
Length 472 words
number_theorysimulationbrute_force

Problem Statement

This archive keeps the full statement, math, and original media on the page.

A program written in the programming language Fractran consists of a list of fractions.

The internal state of the Fractran Virtual Machine is a positive integer, which is initially set to a seed value. Each iteration of a Fractran program multiplies the state integer by the first fraction in the list which will leave it an integer.

For example, one of the Fractran programs that John Horton Conway wrote for prime-generation consists of the following 14 fractions:

Starting with the seed integer 2, successive iterations of the program produce the sequence:
15, 825, 725, 1925, 2275, 425, ..., 68, 4, 30, ..., 136, 8, 60, ..., 544, 32, 240, ...

The powers of 2 that appear in this sequence are 22, 23, 25, ...
It can be shown that all the powers of 2 in this sequence have prime exponents and that all the primes appear as exponents of powers of 2, in proper order!

If someone uses the above Fractran program to solve Project Euler Problem 7 (find the 10001st prime), how many iterations would be needed until the program produces 210001st prime ?

Problem 308: An Amazing Prime-generating Automaton

Mathematical Analysis

Register Machine Encoding

The working number’s prime factorization encodes registers:

  • Primes 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 map to registers a, b, c, d, e, f, g, h, i, j

Each fraction is a conditional register operation:

FractionConditionEffect
17/91d>=1, f>=1d-=1, f-=1, g+=1
78/85c>=1, g>=1a+=1, b+=1, c-=1, f+=1, g-=1
19/51b>=1, g>=1b-=1, g-=1, h+=1
23/38a>=1, h>=1a-=1, h-=1, i+=1
29/33b>=1, e>=1b-=1, e-=1, j+=1
77/29j>=1d+=1, e+=1, j-=1
95/23i>=1c+=1, h+=1, i-=1
77/19h>=1d+=1, e+=1, h-=1
1/17g>=1g-=1
11/13f>=1e+=1, f-=1
13/11e>=1e-=1, f+=1
15/2a>=1a-=1, b+=1, c+=1
1/7d>=1d-=1
55/1alwaysc+=1, e+=1

High-Level Algorithm

The program implements trial division. For each candidate m = 1, 2, 3, …:

  1. Load phase: Transfer a -> b, c (b=m, c=m). Steps: m.
  2. Initialize: c+=1, e+=1. Steps: 1.
  3. Subtraction rounds: Repeatedly subtract the current “divisor” from b, comparing with c.
  4. Resolution: If candidate is prime, output 2^(m+1). If composite, move to next candidate.

Macro-Step Optimization

Each subtraction round at state (a_acc, B, C, D, e=1) has three outcomes:

  1. D+B <= C (divisor fits): Cost = 2B + 2(D+B) + 2 steps. Continue with reduced C.
  2. D+B > C, C > 0 (overflow, next divisor): Cost = 2B + 2C + 2*a_acc + 4 steps.
  3. D+B > C, C = 0 (end of candidate): Cost = 2B + D+B + 2 steps.
    • Prime if D+B = 1 (equivalently B=1, D=0 at entry).
    • Composite otherwise.

This macro-step simulation runs in O(sum of all divisors tested) time, which is fast enough for the 10001st prime.

Correctness

Theorem. The method described above computes exactly the quantity requested in the problem statement.

Proof. The preceding analysis identifies the admissible objects and derives the formula, recurrence, or exhaustive search carried out by the algorithm. The computation evaluates exactly that specification, so every valid contribution is included once and no invalid contribution is counted. Therefore the returned value is the required answer. \square

Complexity

  • Time: O(sum_{m=1}^{p_{10001}} m) in macro-steps, each O(1)
  • Space: O(1)

Answer

1539669807660924\boxed{1539669807660924}

Code

Each problem page includes the exact C++ and Python source files from the local archive.

C++ project_euler/problem_308/solution.cpp
#include <bits/stdc++.h>
using namespace std;

// Macro-step simulation of Conway's PRIMEGAME FRACTRAN program.
// Counts the number of FRACTRAN iterations to produce the 10001st prime.
//
// The FRACTRAN program: 17/91, 78/85, 19/51, 23/38, 29/33, 77/29,
//   95/23, 77/19, 1/17, 11/13, 13/11, 15/2, 1/7, 55/1
// Starting with n=2.
//
// The register machine uses exponents of primes 2,3,5,7,11,13,17,19,23,29
// as registers a,b,c,d,e,f,g,h,i,j.
//
// High-level: processes candidates m=1,2,3,... via trial division.
// Each candidate is tested by repeated subtraction rounds.
//
// State at round entry: a_acc, B=b, C=c, D=d, e=1 (others 0).
// A round:
//   f5/f6 x B:     2B steps.  D += B, B = 0.
//   f11:           1 step.
//   f1/f2 x k:     2k steps.  k = min(D, C). D-=k, C-=k, a_acc+=k, B+=k.
//
//   If D==0: f10: 1 step. Continue next round.
//   If D>0 and C==0 and B>0: f1,f3,f4/f7 x a_acc,f8. Move to next divisor.
//   If D>0 and C==0 and B==0: f1,f9,[f13 x D]. End of candidate.
//     Prime if D==0 after f1 (i.e., old D+B==1). Composite otherwise.

int main() {
    long long total_steps = 0;
    int primes_found = 0;
    int target = 10001;

    // Initial: a=1. f12 x1: b=1,c=1. f14: c=2,e=1. 2 steps.
    total_steps = 2;
    long long a_acc = 0, B = 1, C = 2, D = 0;

    while (primes_found < target) {
        // Phase 1: f5/f6 x B
        total_steps += 2 * B;
        D += B;
        B = 0;

        // Phase 2: f11
        total_steps += 1;

        // Phase 3: f1/f2 x k
        long long k = (D < C) ? D : C;
        total_steps += 2 * k;
        D -= k;
        C -= k;
        a_acc += k;
        B = k;

        if (D == 0) {
            // Case A: f10
            total_steps += 1;
        } else if (B > 0) {
            // Case B1: C == 0, B > 0. Transition to next divisor.
            // f1: D-=1. f3: B-=1. f4/f7 x a_acc. f8: D+=1.
            total_steps += 1 + 1 + 2 * a_acc + 1;
            D -= 1;
            B -= 1;
            C = a_acc;
            D += 1;
            a_acc = 0;
        } else {
            // Case B2: C == 0, B == 0. End of candidate.
            // f1: D-=1. f9: 1. f13 x D.
            D -= 1;
            total_steps += 1 + 1 + D;

            bool is_prime = (D == 0);
            D = 0;

            if (is_prime) {
                primes_found++;
                if (primes_found == target) break;
            }

            // Load next candidate: f12 x a_acc + f14.
            total_steps += a_acc + 1;
            B = a_acc;
            C = a_acc + 1;
            D = 0;
            a_acc = 0;
        }
    }

    printf("%lld\n", total_steps);
    return 0;
}