Multiple-precision arithmetic library providing fast GMP, MPFR, and MPC interfaces for Python
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
gmpy2 provides comprehensive random number generation capabilities for all multiple-precision types. The random number system uses configurable random state objects and provides various distributions suitable for cryptographic, statistical, and mathematical applications.
Random state objects manage the internal state of random number generators, enabling reproducible sequences and parallel random number generation.
class random_state:
def __init__(self, seed=0):
"""
Create a random number generator state.
Args:
seed: Seed value for initialization (int, default 0)
Note:
Different seeds produce different random sequences
Same seed produces identical sequences (reproducible)
"""Functions for generating random integers with various distributions.
def mpz_random(state, n):
"""
Generate random integer in range [0, n).
Args:
state: random_state object
n: Upper bound (exclusive, must be positive)
Returns:
mpz: Random integer 0 <= result < n
Note:
Uniform distribution over the specified range
"""
def mpz_urandomb(state, n):
"""
Generate random integer with exactly n random bits.
Args:
state: random_state object
n: Number of random bits (non-negative integer)
Returns:
mpz: Random integer in range [0, 2^n)
Note:
Each bit is independently random with probability 1/2
"""
def mpz_rrandomb(state, n):
"""
Generate random integer with at most n bits, different distribution.
Args:
state: random_state object
n: Maximum number of bits
Returns:
mpz: Random integer with different bit distribution than urandomb
Note:
Provides different statistical properties than urandomb
"""Functions for generating random floating-point numbers with various precisions and distributions.
def mpfr_random(state):
"""
Generate random float in [0, 1) with current precision.
Args:
state: random_state object
Returns:
mpfr: Random float 0 <= result < 1
Note:
Uses current context precision for result
Uniform distribution over [0, 1)
"""
def mpfr_grandom(state):
"""
Generate pair of Gaussian random numbers (Box-Muller method).
Args:
state: random_state object
Returns:
tuple: (x, y) where both are normally distributed mpfr values
Note:
Standard normal distribution (mean=0, variance=1)
More efficient than generating two separate normal values
"""
def mpfr_nrandom(state):
"""
Generate single normal (Gaussian) random number.
Args:
state: random_state object
Returns:
mpfr: Normally distributed random float
Note:
Standard normal distribution (mean=0, variance=1)
Uses current context precision
"""Function for generating random complex numbers.
def mpc_random(state):
"""
Generate random complex number.
Args:
state: random_state object
Returns:
mpc: Complex number with random real and imaginary parts
Note:
Both real and imaginary parts are uniform in [0, 1)
Uses current context precision for both parts
"""import gmpy2
# Create random state with seed for reproducibility
rstate = gmpy2.random_state(12345)
# Generate random integers
print("Random integers:")
for i in range(5):
# Random integer in range [0, 1000)
rand_int = gmpy2.mpz_random(rstate, 1000)
print(f" Random [0, 1000): {rand_int}")
# Generate random integers with specific bit lengths
print("\nRandom integers with specific bit lengths:")
for bits in [8, 16, 32]:
rand_bits = gmpy2.mpz_urandomb(rstate, bits)
print(f" {bits:2d} bits: {rand_bits} (hex: {hex(rand_bits)})")import gmpy2
def generate_sequence(seed, count=5):
"""Generate a sequence of random numbers with given seed."""
rstate = gmpy2.random_state(seed)
sequence = []
for _ in range(count):
sequence.append(gmpy2.mpz_random(rstate, 100))
return sequence
# Same seed produces identical sequences
seed = 42
seq1 = generate_sequence(seed)
seq2 = generate_sequence(seed)
print(f"Sequence 1 (seed {seed}): {seq1}")
print(f"Sequence 2 (seed {seed}): {seq2}")
print(f"Sequences identical: {seq1 == seq2}")
# Different seed produces different sequence
seq3 = generate_sequence(seed + 1)
print(f"Sequence 3 (seed {seed + 1}): {seq3}")
print(f"Different from seq1: {seq1 != seq3}")import gmpy2
# Generate random floats at different precisions
rstate = gmpy2.random_state(98765)
precisions = [24, 53, 100, 200]
print("Random floats at different precisions:")
for prec in precisions:
with gmpy2.local_context(precision=prec):
rand_float = gmpy2.mpfr_random(rstate)
print(f" {prec:3d} bits: {rand_float}")
# Generate multiple random floats
print("\nMultiple random floats (53-bit precision):")
with gmpy2.local_context(precision=53):
for i in range(5):
rand_float = gmpy2.mpfr_random(rstate)
print(f" Random [0, 1): {rand_float}")import gmpy2
rstate = gmpy2.random_state(54321)
# Generate individual normal random numbers
print("Individual normal random numbers:")
with gmpy2.local_context(precision=80):
for i in range(5):
normal = gmpy2.mpfr_nrandom(rstate)
print(f" N(0,1): {normal}")
# Generate pairs of normal random numbers (more efficient)
print("\nPairs of normal random numbers:")
with gmpy2.local_context(precision=80):
for i in range(3):
x, y = gmpy2.mpfr_grandom(rstate)
print(f" Pair {i+1}: ({x}, {y})")import gmpy2
rstate = gmpy2.random_state(11111)
print("Random complex numbers:")
with gmpy2.local_context(precision=60):
for i in range(5):
rand_complex = gmpy2.mpc_random(rstate)
print(f" Complex: {rand_complex}")
print(f" Magnitude: {gmpy2.abs(rand_complex)}")
print(f" Phase: {gmpy2.phase(rand_complex)}")import gmpy2
def analyze_random_bits(state, bit_length, count=1000):
"""Analyze distribution of random bits."""
bit_counts = [0] * bit_length
for _ in range(count):
rand_num = gmpy2.mpz_urandomb(state, bit_length)
for bit_pos in range(bit_length):
if gmpy2.bit_test(rand_num, bit_pos):
bit_counts[bit_pos] += 1
return bit_counts
# Analyze 8-bit random numbers
rstate = gmpy2.random_state(99999)
bit_analysis = analyze_random_bits(rstate, 8, 10000)
print("Bit position analysis (8-bit random numbers, 10000 samples):")
for pos, count in enumerate(bit_analysis):
percentage = (count / 10000) * 100
print(f" Bit {pos}: {count:4d} set ({percentage:5.1f}%)")
# Should be approximately 50% for each bit positionimport gmpy2
def generate_large_random_prime_candidate(bits, rstate):
"""Generate a large random odd number (prime candidate)."""
# Generate random number with specified bits
candidate = gmpy2.mpz_urandomb(rstate, bits)
# Ensure it's odd (required for prime)
candidate = gmpy2.bit_set(candidate, 0)
# Ensure high bit is set (full bit length)
candidate = gmpy2.bit_set(candidate, bits - 1)
return candidate
# Generate potential cryptographic prime candidates
rstate = gmpy2.random_state(12345678)
print("Large prime candidates for cryptographic use:")
for key_size in [512, 1024, 2048]:
candidate = generate_large_random_prime_candidate(key_size, rstate)
# Quick primality check
is_prime = gmpy2.is_prime(candidate, 25)
print(f"\n{key_size}-bit candidate:")
print(f" Hex: {hex(candidate)[:50]}...")
print(f" Bit length: {gmpy2.bit_length(candidate)}")
print(f" Is prime: {is_prime}")
if is_prime:
print(f" Found prime!")
break # In practice, you'd save this primeimport gmpy2
def random_in_range(state, min_val, max_val):
"""Generate random number in specific range [min_val, max_val]."""
if min_val >= max_val:
raise ValueError("min_val must be less than max_val")
range_size = max_val - min_val + 1
return gmpy2.mpz_random(state, range_size) + min_val
# Generate random numbers in custom ranges
rstate = gmpy2.random_state(777)
ranges = [
(100, 200), # Small range
(1000, 9999), # 4-digit numbers
(2**30, 2**31), # Large range
]
print("Random numbers in custom ranges:")
for min_val, max_val in ranges:
for _ in range(3):
rand_val = random_in_range(rstate, min_val, max_val)
print(f" [{min_val}, {max_val}]: {rand_val}")import gmpy2
def estimate_pi_monte_carlo(n_points, precision=100):
"""Estimate π using Monte Carlo method with high precision."""
rstate = gmpy2.random_state(314159)
inside_circle = 0
with gmpy2.local_context(precision=precision):
for _ in range(n_points):
# Generate point in unit square [0,1) × [0,1)
x = gmpy2.mpfr_random(rstate)
y = gmpy2.mpfr_random(rstate)
# Check if point is inside unit circle
if x*x + y*y < 1:
inside_circle += 1
# Estimate π = 4 × (points inside circle) / (total points)
pi_estimate = 4 * gmpy2.mpfr(inside_circle) / n_points
return pi_estimate
# Estimate π with different sample sizes
print("Monte Carlo estimation of π:")
for n in [1000, 10000, 100000]:
pi_est = estimate_pi_monte_carlo(n, precision=80)
actual_pi = gmpy2.const_pi(precision=80)
error = abs(pi_est - actual_pi)
print(f" {n:6d} points: {pi_est}")
print(f" Error: {error}")import gmpy2
def create_independent_generators(master_seed, count):
"""Create multiple independent random number generators."""
generators = []
# Use master generator to create seeds for independent generators
master_rstate = gmpy2.random_state(master_seed)
for i in range(count):
# Generate a unique seed for each generator
seed = gmpy2.mpz_random(master_rstate, 2**32)
generators.append(gmpy2.random_state(int(seed)))
return generators
# Create independent generators for parallel use
generators = create_independent_generators(123456, 4)
print("Independent random number generators:")
for i, gen in enumerate(generators):
sequence = []
for _ in range(5):
sequence.append(gmpy2.mpz_random(gen, 1000))
print(f" Generator {i}: {sequence}")
# Verify independence (sequences should be different)
all_sequences = []
for gen in generators:
seq = [gmpy2.mpz_random(gen, 100) for _ in range(10)]
all_sequences.append(seq)
print(f"\nAll sequences different: {len(set(map(tuple, all_sequences))) == len(all_sequences)}")Install with Tessl CLI
npx tessl i tessl/pypi-gmpy2