Tuesday, May 26, 2026Today's Paper

Omni Apps

Linear Congruential Generator: Math, Python, and Pitfalls
May 26, 2026 · 15 min read

Linear Congruential Generator: Math, Python, and Pitfalls

Discover how the linear congruential generator works. Learn the math behind this modulo generator, run Python code, and explore why modern applications avoid it.

May 26, 2026 · 15 min read
AlgorithmsMathematicsSoftware Development

In the early days of computing, generating random-looking numbers on highly constrained hardware was one of the most formidable challenges facing computer scientists. Enter the linear congruential generator (LCG). Originally proposed by mathematician D. H. Lehmer in 1951, the LCG is one of the oldest and most widely studied algorithms for generating pseudo-random sequences.

Though modern cryptographic requirements and complex simulations have largely left the standard LCG behind, it remains a foundational topic in computer science. In this comprehensive guide, we will break down the mathematical inner workings of this classic modulo generator, analyze a step-by-step mathematical example, provide robust Python implementations, and discuss how to mitigate its notorious weaknesses.


1. What is a Linear Congruential Generator?

A linear congruential generator is a class of pseudo-random number generator (PRNG) algorithms that produce a sequence of numbers using a discontinuous piecewise linear equation. The sequence is defined by a simple recurrence relation:

$$X_{n+1} = (aX_n + c) \pmod m$$

To understand how this formula works, we need to define its four critical parameters:

  1. $m$ (The Modulus): A positive integer ($m > 0$) that defines the range of the generated sequence and establishes the maximum possible period of the generator.
  2. $a$ (The Multiplier): An integer ($0 < a < m$) that scales the previous state.
  3. $c$ (The Increment): An integer ($0 \le c < m$) added during each iteration.
  4. $X_0$ (The Seed or Start Value): An integer ($0 \le X_0 < m$) that initializes the sequence.

Because the equation relies on the modulo operation, the output $X_{n+1}$ will always be an integer between $0$ and $m - 1$. This is why the algorithm is often fundamentally referred to as a modulo generator.

The Role of Modulo Arithmetic

Modulo arithmetic forces the sequence to wrap around. Think of it like a clock face: when the numbers get too large, they cycle back to the beginning. This wrap-around effect is what prevents the numbers from growing infinitely and forces them to repeat a cycle. The length of this cycle before the sequence begins repeating itself is known as the period of the generator.


2. Multiplicative vs. Mixed Congruential Generators

Linear congruential generators generally fall into two categories depending on the value of the increment ($c$):

Mixed Congruential Generator ($c \neq 0$)

When the increment $c$ is non-zero, the algorithm is called a mixed congruential generator. The presence of the addition term $c$ allows the generator to potentially achieve a full period of $m$. Under the right mathematical conditions, a mixed generator can cycle through every single integer from $0$ to $m-1$ exactly once before repeating, regardless of the seed value $X_0$.

Multiplicative Congruential Generator ($c = 0$)

If the increment $c$ is set to zero ($c = 0$), the formula simplifies to:

$$X_{n+1} = aX_n \pmod m$$

This simplified version is known as a multiplicative congruential generator (MCG) or a Lehmer random number generator.

While an MCG has one fewer parameter to configure, it comes with a major mathematical limitation: it can never achieve a full period of $m$. Because $c = 0$, if the state $X_n$ ever hits $0$, the generator will get permanently stuck on $0$ ($a \times 0 = 0$). Therefore, the seed $X_0$ cannot be $0$, and the number $0$ can never be part of the sequence. Consequently, the absolute maximum period for an MCG is $m - 1$.


3. Maximizing the Period: The Hull-Dobell Theorem

When designing an LCG, our primary goal is to make the period as long as possible. If the period is too short, the generator will quickly repeat its sequence, making the "random" numbers highly predictable.

To achieve a full period of length $m$ (meaning the generator yields every integer from $0$ to $m-1$ exactly once before repeating), the parameters must satisfy the Hull-Dobell Theorem. This theorem states that an LCG will have a full period of $m$ for all seed values if and only if the following three conditions are met:

  1. $c$ and $m$ are relatively prime (coprime): The greatest common divisor of $c$ and $m$ must be $1$ (i.e., $\gcd(c, m) = 1$).
  2. $a - 1$ is divisible by all prime factors of $m$: Every prime number that divides $m$ must also divide $a - 1$.
  3. $a - 1$ is a multiple of $4$ if $m$ is a multiple of $4$: If the modulus $m$ is divisible by $4$, then $a - 1$ must also be divisible by $4$.

Applying the Hull-Dobell Theorem: An Example

Let’s verify if we can design a full-period generator with a modulus of $m = 8$:

  • Since $m = 8$ (which is $2^3$), the only prime factor of $m$ is $2$.
  • Condition 1: We must choose an increment $c$ that is coprime to $8$. Let’s pick $c = 3$. Since $\gcd(3, 8) = 1$, this condition is satisfied.
  • Condition 2: The prime factor of $m$ is $2$. Therefore, $a - 1$ must be divisible by $2$ (meaning $a$ must be an odd number). Let's tentatively pick $a = 5$. $a-1 = 4$, which is indeed divisible by $2$.
  • Condition 3: Since $m = 8$ is divisible by $4$, $a - 1$ must be divisible by $4$. Our choice of $a = 5$ gives $a - 1 = 4$, which is divisible by $4$. All conditions are satisfied!

If we set $m = 8$, $a = 5$, and $c = 3$, the Hull-Dobell theorem guarantees that our generator will cycle through all $8$ states before repeating, regardless of the seed we choose.


4. Step-by-Step Linear Congruential Generator Example

Let's put our math to the test and construct a step-by-step linear congruential generator example using the parameters we verified above:

  • Modulus ($m$) = $8$
  • Multiplier ($a$) = $5$
  • Increment ($c$) = $3$
  • Seed ($X_0$) = $4$

Let’s manually calculate the first 9 iterations to observe the full cycle and watch where it begins to repeat. If you were writing a manual linear congruential generator calculator program, this is the exact loop it would execute:

  • Iteration 1: $$X_1 = (5 \times X_0 + 3) \pmod 8$$ $$X_1 = (5 \times 4 + 3) \pmod 8 = 23 \pmod 8$$ Since $23 = (2 \times 8) + 7$, the remainder is $7$. $X_1 = 7$

  • Iteration 2: $$X_2 = (5 \times 7 + 3) \pmod 8 = 38 \pmod 8$$ Since $38 = (4 \times 8) + 6$, the remainder is $6$. $X_2 = 6$

  • Iteration 3: $$X_3 = (5 \times 6 + 3) \pmod 8 = 33 \pmod 8$$ Since $33 = (4 \times 8) + 1$, the remainder is $1$. $X_3 = 1$

  • Iteration 4: $$X_4 = (5 \times 1 + 3) \pmod 8 = 8 \pmod 8$$ Since $8 = (1 \times 8) + 0$, the remainder is $0$. $X_4 = 0$

  • Iteration 5: $$X_5 = (5 \times 0 + 3) \pmod 8 = 3 \pmod 8$$ Since $3$ is less than $8$, the remainder is $3$. $X_5 = 3$

  • Iteration 6: $$X_6 = (5 \times 3 + 3) \pmod 8 = 18 \pmod 8$$ Since $18 = (2 \times 8) + 2$, the remainder is $2$. $X_6 = 2$

  • Iteration 7: $$X_7 = (5 \times 2 + 3) \pmod 8 = 13 \pmod 8$$ Since $13 = (1 \times 8) + 5$, the remainder is $5$. $X_7 = 5$

  • Iteration 8: $$X_8 = (5 \times 5 + 3) \pmod 8 = 28 \pmod 8$$ Since $28 = (3 \times 8) + 4$, the remainder is $4$. $X_8 = 4$

  • Iteration 9: $$X_9 = (5 \times 4 + 3) \pmod 8 = 23 \pmod 8 = 7$$ $X_9 = 7$

Analysis of the Output Sequence

Let’s look at the complete sequence of generated states: $$\mathbf{4} \rightarrow 7 \rightarrow 6 \rightarrow 1 \rightarrow 0 \rightarrow 3 \rightarrow 2 \rightarrow 5 \rightarrow \mathbf{4} \rightarrow 7 \dots$$

Observe how the sequence generated every integer from $0$ to $7$ exactly once before returning to the seed value of $4$ on the eighth iteration. This is a perfect demonstration of a full-period mixed congruential generator.


5. Implementing a Linear Congruential Generator in Python

If you are searching for a linear congruential generator python implementation, you likely want a practical, reusable snippet. Below, we provide an object-oriented Python implementation that leverages Python's generator pattern (yield) to supply an infinite stream of pseudo-random numbers.

To make this code useful for real-world simulation work, we will use widely-accepted production-grade parameters. Specifically, we will use the parameters popularized by Numerical Recipes:

  • $m = 2^{32}$ (a $32$-bit unsigned integer modulus)
  • $a = 1664525$
  • $c = 1013904223$

The Python Code

class LinearCongruentialGenerator:
    """
    A class-based implementation of a Linear Congruential Generator (LCG).
    Defaults to the popular Numerical Recipes parameters.
    """
    def __init__(self, seed: int, a: int = 1664525, c: int = 1013904223, m: int = 2**32):
        if not (0 <= seed < m):
            raise ValueError(f"Seed must be between 0 and {m - 1} inclusive.")
        self.state = seed
        self.a = a
        self.c = c
        self.m = m

    def next_int(self) -> int:
        """Generates the next random integer in the range [0, m-1]."""
        self.state = (self.a * self.state + self.c) % self.m
        return self.state

    def next_float(self) -> float:
        """Generates a floating-point number scaled to the range [0.0, 1.0)."""
        return self.next_int() / self.m

    def generator(self):
        """An infinite generator function returning pseudo-random integers."""
        while True:
            yield self.next_int()

# --- Practical Usage Example ---
if __name__ == "__main__":
    # Initialize the generator with a seed of 42
    lcg = LinearCongruentialGenerator(seed=42)
    
    print("First 5 pseudo-random integers (0 to 2^32 - 1):")
    for _ in range(5):
        print(f"  - {lcg.next_int()}")
        
    print("\nFirst 5 pseudo-random floats (scaled [0.0, 1.0)): ")
    for _ in range(5):
        print(f"  - {lcg.next_float():.6f}")

How to Scale LCG Outputs

By default, our Python implementation's next_int() method returns massive integers bounded only by the modulus $2^{32}$. To map these numbers to a practical range—such as rolling a 6-sided die—we can use simple scaling arithmetic:

def roll_die(lcg_instance) -> int:
    # Map the output to an integer between 1 and 6 inclusive
    return 1 + (lcg_instance.next_int() % 6)

Alternatively, you can multiply the normalized float returned by next_float() by your desired range size and take the floor value.


6. Combined Linear Congruential Generators: Scaling Up

Because a simple LCG has serious structural weaknesses, researchers looked for ways to build stronger generators without sacrificing speed. This search led to the development of the combined linear congruential generator (CLCG).

A CLCG works by running two or more independent linear congruential generators in parallel and combining their output sequences. Typically, we choose the moduli of the component generators to be coprime, distinct prime numbers.

Let’s look at a popular combination method developed by Pierre L'Ecuyer. Suppose we have two independent LCG sequences, $Y_n$ and $Z_n$, governed by two different prime moduli, $m_1$ and $m_2$:

$$Y_{n+1} = a_1 Y_n \pmod{m_1}$$ $$Z_{n+1} = a_2 Z_n \pmod{m_2}$$

We can combine their states to produce a new sequence $W_n$ using the following formula:

$$W_n = (Y_n - Z_n) \pmod{m_1 - 1}$$

If $W_n > 0$, our final pseudo-random output is $W_n / m_1$. If $W_n = 0$, we map it to $(m_1 - 1) / m_1$.

Why Use Combined LCGs?

By combining the two generators, we achieve two major benefits:

  1. Massive Periods: The period of the combined generator is the least common multiple of the individual periods. For moderate-sized prime moduli, the combined period can easily exceed $10^{18}$, which is far larger than a standard single-modulus LCG can manage.
  2. Improved Statistical Properties: Combining the sequences disrupts the highly structured, predictable patterns inherent in a single LCG, allowing the resulting numbers to pass more rigorous statistical tests of randomness.

7. The Fatal Flaws: Why Modern Systems Avoid Raw LCGs

Despite their historical significance and ease of implementation, raw LCGs are rarely used in modern production environments. If you search for a linear congruential generator online tool, it is likely for homework validation or educational purposes. Understanding why they fail is a crucial concept in modern computer science.

1. Zero Cryptographic Security

An LCG is entirely predictable. If an attacker can observe just a tiny chunk of the output sequence, they can easily solve a system of linear equations to determine the multiplier ($a$), increment ($c$), and modulus ($m$). Once these parameters are known, the attacker can reconstruct the state and predict every single future number. Therefore, never use an LCG for cryptography, password generation, security tokens, or hashing salts.

2. "Random Numbers Fall Mainly in the Plains"

In 1968, mathematician George Marsaglia published a landmark paper proving that the outputs of LCGs exhibit a fatal dimensional defect.

If you take consecutive values from an LCG and plot them as coordinate points in a multi-dimensional space (e.g., plotting $3$-tuples $(X_n, X_{n+1}, X_{n+2})$ in a $3$D grid), the points do not fill the space uniformly. Instead, they align themselves onto a relatively small number of parallel hyperplanes.

This behavior is known as the spectral defect of LCGs. If you use a raw LCG for a Monte Carlo simulation or a physics model, your simulation may yield highly inaccurate results because large volumes of your multi-dimensional coordinate space are left completely untouched.

[Standard Uniform Distribution]        [LCG Spectral Test Failure]
+-----------------------------+        +-----------------------------+
|  .   .  .   .  .   .   .  . |        | /  /  /  /  /  /  /  /  /  /|
| .  .   .  .   .  .   .  .  .|        |/  /  /  /  /  /  /  /  /  / |
|   .  .   .  .   .  .   .  . |  --->  |  /  /  /  /  /  /  /  /  /  |
|  .  .   .  .   .  .   .  .  |        | /  /  /  /  /  /  /  /  /  /|
| .   .  .   .  .   .   .  .  |        |/  /  /  /  /  /  /  /  /  / |
+-----------------------------+        +-----------------------------+
(Smooth, uniform distribution)         (Points cluster on rigid planes)

3. Modulo Power-of-Two Bit Weakness

Many implementations use a power of two for the modulus (like $m = 2^{32}$ or $2^{64}$) because computers can calculate division modulo $2^k$ incredibly fast using simple bitwise masking.

However, when $m$ is a power of two, the lowest-order bits of the output sequence repeat on a much shorter period than the overall generator. The least significant bit (the last bit) alternates strictly between $0$ and $1$ (even, odd, even, odd). If your application relies on checking if a number is odd or even to make a decision, a power-of-two LCG will yield a completely non-random, alternating pattern.

What do we use instead?

Modern programming languages have replaced LCGs with far superior algorithms:

  • Mersenne Twister (MT19937): Used by default in Python's random module, PHP, and Ruby. It has a massive period of $2^{19937} - 1$ and excellent statistical uniformity.
  • PCG (Permuted Congruential Generator): A modern derivative of the LCG. It takes the fast state transition of an LCG but applies a cryptographic-style permutation function to the output to eliminate the spectral defect and conceal the underlying state.
  • Xoshiro / Xoroshiro: Extremely fast shift-register generators favored in modern games and engines like V8 (JavaScript) for their low memory footprint and high speed.
  • CSPRNGs (Cryptographically Secure Pseudo-Random Number Generators): Algorithms like ChaCha20, used by OS-level entropy pools (/dev/urandom), designed specifically to resist state-reconstruction attacks.

8. Frequently Asked Questions

Can I make an online linear congruential generator calculator in JavaScript?

Yes, you can easily implement the LCG logic in JavaScript. Since JavaScript represents numbers as double-precision floats, you must be careful with large integer multiplications to avoid precision loss above $2^{53} - 1$. Using JavaScript's BigInt class is the cleanest way to build a reliable linear congruential generator calculator online.

What is the difference between a pseudo-random number generator and a true random number generator?

A pseudo-random number generator (PRNG) like an LCG uses a deterministic mathematical formula. Given the same initial seed, it will always output the exact same sequence of numbers. A True Random Number Generator (TRNG) harvests entropy from physical, unpredictable hardware events, such as thermal noise, atmospheric static, or radioactive decay.

Is it possible to find a "perfect" set of parameters for an LCG?

There is no perfect set of parameters, only trade-offs. You can select parameters that satisfy the Hull-Dobell theorem to guarantee a full period, but the spectral test will always show some degree of hyperplanar grouping. To achieve better statistical results, you must either use a Combined LCG or transition to a modern algorithm like PCG.

Why is the seed value so important?

The seed determines the starting point of the generator's path through its cycle. If you initialize an LCG with the exact same seed on two different machines, they will produce identical sequences of pseudo-random numbers. This determinism is highly useful for debugging simulations, procedural generation in video games, and automated testing.


Summary of Key Takeaways

  • The linear congruential generator relies on the simple recurrence formula $X_{n+1} = (aX_n + c) \pmod m$.
  • An LCG is classified as a modulo generator because the modulo operator bounds the values and dictates the period cycle.
  • If $c = 0$, it is a multiplicative congruential generator (MCG); if $c \neq 0$, it is a mixed congruential generator.
  • To achieve a full period of length $m$, the parameters must satisfy the Hull-Dobell Theorem.
  • While they are incredibly fast and require minimal memory, raw LCGs fail modern statistical tests due to the spectral defect (points grouping onto parallel hyperplanes) and are fundamentally unsafe for cryptography.
  • Modern systems use advanced alternatives like PCG, Mersenne Twister, or combined linear congruential generators to get large periods and high-quality randomness.
Related articles
High-Precision Ounce Calculator: Fluid, Dry & NIST Standards
High-Precision Ounce Calculator: Fluid, Dry & NIST Standards
Master measurements with our ultimate ounce calculator guide. Learn standard conversions, baking math, and the scientific NIST standards of fluid metrology.
May 26, 2026 · 11 min read
Read →
Master the Compound Percentage: Formulas, Calculations, and Guide
Master the Compound Percentage: Formulas, Calculations, and Guide
Learn how to calculate a compound percentage with our step-by-step guide. Master the compound percentage formula and unlock the secrets of compounding growth.
May 25, 2026 · 13 min read
Read →
The Ultimate Percentage Formula Chart: Quick Reference Guide
The Ultimate Percentage Formula Chart: Quick Reference Guide
Master every math, data, and Excel calculation with our ultimate percentage formula chart. Includes conversion tables, pie chart math, and mental hacks!
May 25, 2026 · 18 min read
Read →
5 Random Numbers Between 1 and 50: The Ultimate Generator Guide
5 Random Numbers Between 1 and 50: The Ultimate Generator Guide
Need to generate 5 random numbers between 1 and 50? Learn the math of random selection, step-by-step Excel guides, and secure programming solutions.
May 25, 2026 · 12 min read
Read →
KL to Pounds Conversion: The Ultimate Weight & Volume Guide
KL to Pounds Conversion: The Ultimate Weight & Volume Guide
Need to complete a kl to pounds conversion? Master how to convert kilos (kls) or kiloliters (kl) to pounds (lbs) with exact formulas, tables, and mental math.
May 23, 2026 · 12 min read
Read →
You May Also Like