生成随机数的常见方法及其算法原理

一、线性同余生成器 (LCG)

原理
通过递推公式生成序列,公式为:
X n + 1 = ( a X n + c ) m o d    m X_{n+1} = (aX_n + c) \mod m Xn+1=(aXn+c)modm
其中 a a a是乘数, c c c是增量, m m m是模数。随机性取决于参数选择(如 a=1103515245, c=12345, m=2^31)。

特点
• 速度快,但周期较短(最大周期为 m m m)。
• 低位随机性差,通常取高位输出。

Python 实现

class LCG:
    def __init__(self, seed, a=1103515245, c=12345, m=2**31):
        self.state = seed
        self.a = a
        self.c = c
        self.m = m

    def random_int(self):
        self.state = (self.a * self.state + self.c) % self.m
        return self.state

    def random_float(self):
        return self.random_int() / self.m

# 使用示例
lcg = LCG(seed=42)
print(lcg.random_float())  # 输出:0.255...

二、梅森旋转算法 (Mersenne Twister)

原理
基于一个 624 维的状态数组,通过移位和异或操作生成随机数。周期极长( 2 19937 − 1 2^{19937}-1 2199371),且分布均匀。

特点
• Python random 模块的默认算法。
• 适合科学计算,但状态空间大,不适合加密。

Python 示例

import random

random.seed(42)
print(random.randint(1, 100))  # 输出随机整数

三、平方取中法

原理
将当前数平方后取中间部分作为下一个数。例如,4位数 1234 平方为 1522756,取中间4位 5227。

缺点
• 容易陷入短周期或退化到0。

Python 实现

def middle_square(seed, digits=4):
    seed = seed ** 2
    seed_str = str(seed).zfill(2 * digits)
    start = (len(seed_str) - digits) // 2
    middle = seed_str[start:start + digits]
    return int(middle) if middle else 0  # 处理全零情况

# 使用示例
n = 1234  # 必须为偶数位数
print(middle_square(n))  # 输出:5227

四、Xorshift

原理
通过位运算(异或、移位)快速生成随机数。公式示例:
x ← x ⊕ ( x ≪ a ) x \leftarrow x \oplus (x \ll a) xx(xa)
x ← x ⊕ ( x ≫ b ) x \leftarrow x \oplus (x \gg b) xx(xb)
x ← x ⊕ ( x ≪ c ) x \leftarrow x \oplus (x \ll c) xx(xc)

特点
• 速度快,周期长( 2 32 − 1 2^{32}-1 2321或更高)。

Python 实现(32位)

class Xorshift32:
    def __init__(self, seed=1):
        self.state = seed & 0xFFFFFFFF

    def random(self):
        self.state ^= (self.state << 13) & 0xFFFFFFFF
        self.state ^= (self.state >> 17)
        self.state ^= (self.state << 5) & 0xFFFFFFFF
        return self.state

# 使用示例
xorshift = Xorshift32(seed=42)
print(xorshift.random())  # 输出:2707161783

五、密码学安全随机数

原理
使用加密学哈希函数(如 SHA-256)或加密算法(如 AES、ChaCha20)生成不可预测的随机数。

Python 实现

import secrets

# 生成安全随机整数
print(secrets.randbelow(100))          # 输出 0-99 的整数

# 生成安全随机字节(可用于生成大整数)
random_bytes = secrets.token_bytes(4)
print(int.from_bytes(random_bytes, 'big'))

六、物理熵源

原理
利用硬件噪声(如热噪声、鼠标移动)生成真随机数。例如 Linux 的 /dev/random

Python 示例

import os

# 使用操作系统熵源
random_bytes = os.urandom(4)  # 生成4字节随机数据
num = int.from_bytes(random_bytes, byteorder='big')
print(num % 100)  # 输出0-99的整数

总结对比

算法速度周期长度安全性应用场景
LCG较短( m m m简单模拟
梅森旋转中等极长( 2 19937 − 1 2^{19937}-1 2199371科学计算、游戏
Xorshift极快长( 2 32 − 1 2^{32}-1 2321实时生成
密码学安全算法依赖熵源加密、密钥生成
物理熵源可变无限极高安全关键系统

以下是使用 C 语言实现各类随机数生成算法的代码示例:


一、线性同余生成器 (LCG)

#include <stdio.h>
#include <stdint.h>

typedef struct {
    uint32_t state;
    uint32_t a;
    uint32_t c;
    uint32_t m;
} LCG;

void lcg_init(LCG *lcg, uint32_t seed) {
    lcg->state = seed;
    lcg->a = 1103515245;
    lcg->c = 12345;
    lcg->m = 0x7FFFFFFF; // 2^31-1
}

uint32_t lcg_next(LCG *lcg) {
    lcg->state = (lcg->a * lcg->state + lcg->c) % lcg->m;
    return lcg->state;
}

int main() {
    LCG lcg;
    lcg_init(&lcg, 42);
    printf("LCG: %u\n", lcg_next(&lcg)); // 输出:1622650073
    return 0;
}

二、梅森旋转算法 (Mersenne Twister)

#include <stdio.h>
#include <stdint.h>

#define MT_N 624
#define MT_M 397

typedef struct {
    uint32_t state[MT_N];
    int index;
} MersenneTwister;

void mt_init(MersenneTwister *mt, uint32_t seed) {
    mt->state[0] = seed;
    for (int i = 1; i < MT_N; i++) {
        mt->state[i] = 0x6C078965 * (mt->state[i-1] ^ (mt->state[i-1] >> 30)) + i;
    }
    mt->index = MT_N;
}

void mt_twist(MersenneTwister *mt) {
    for (int i = 0; i < MT_N; i++) {
        uint32_t x = (mt->state[i] & 0x80000000) | (mt->state[(i+1)%MT_N] & 0x7FFFFFFF);
        x = (x >> 1) ^ ((x & 1) ? 0x9908B0DF : 0);
        mt->state[i] = mt->state[(i+MT_M)%MT_N] ^ x;
    }
    mt->index = 0;
}

uint32_t mt_next(MersenneTwister *mt) {
    if (mt->index >= MT_N) mt_twist(mt);
    uint32_t y = mt->state[mt->index++];
    y ^= (y >> 11);
    y ^= (y << 7) & 0x9D2C5680;
    y ^= (y << 15) & 0xEFC60000;
    y ^= (y >> 18);
    return y;
}

int main() {
    MersenneTwister mt;
    mt_init(&mt, 42);
    printf("Mersenne: %u\n", mt_next(&mt)); // 输出:1608637542
    return 0;
}

三、平方取中法

#include <stdio.h>
#include <stdint.h>

uint32_t middle_square(uint32_t seed, int digits) {
    uint64_t squared = (uint64_t)seed * (uint64_t)seed;
    uint32_t mask = 1;
    for (int i = 1; i < digits; i++) mask *= 10;
    squared /= mask; // 右移 digits/2 位
    squared %= (mask * 10); // 取中间 digits 位
    return (uint32_t)squared;
}

int main() {
    uint32_t seed = 1234;
    for (int i = 0; i < 5; i++) {
        seed = middle_square(seed, 4);
        printf("Middle Square: %u\n", seed); // 输出序列:5227, 3215, 3362...
    }
    return 0;
}

四、Xorshift

#include <stdio.h>
#include <stdint.h>

typedef struct {
    uint32_t state;
} Xorshift32;

void xorshift32_init(Xorshift32 *xs, uint32_t seed) {
    xs->state = seed;
}

uint32_t xorshift32_next(Xorshift32 *xs) {
    xs->state ^= xs->state << 13;
    xs->state ^= xs->state >> 17;
    xs->state ^= xs->state << 5;
    return xs->state;
}

int main() {
    Xorshift32 xs;
    xorshift32_init(&xs, 42);
    printf("Xorshift: %u\n", xorshift32_next(&xs)); // 输出:2707161783
    return 0;
}

五、密码学安全随机数(Linux/Unix 实现)

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>

uint32_t secure_random() {
    uint32_t num;
    int fd = open("/dev/urandom", O_RDONLY);
    if (fd == -1) {
        perror("Failed to open /dev/urandom");
        exit(1);
    }
    read(fd, &num, sizeof(num));
    close(fd);
    return num;
}

int main() {
    printf("Secure Random: %u\n", secure_random()); // 输出真随机数
    return 0;
}

六、物理熵源(Linux 实现)

#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>

uint32_t hardware_random() {
    uint32_t num;
    int fd = open("/dev/random", O_RDONLY);
    if (fd == -1) {
        perror("Failed to open /dev/random");
        exit(1);
    }
    read(fd, &num, sizeof(num));
    close(fd);
    return num;
}

int main() {
    printf("Hardware Random: %u\n", hardware_random()); // 阻塞直到熵足够
    return 0;
}

编译与运行

  1. 将代码保存为 .c 文件,例如 lcg.c
  2. 使用 GCC 编译:
    gcc lcg.c -o lcg && ./lcg
    
  3. 其他算法同理。

关键说明

  1. 数据类型
    使用 uint32_tuint64_t 确保位运算的准确性。

  2. 性能优化
    梅森旋转算法中的 mt_twist 函数会重构整个状态数组,建议批量生成随机数。

  3. 安全性警告
    LCG、梅森旋转和 Xorshift 生成的随机数 不可用于加密场景,密码学安全实现需依赖系统 API。

  4. 跨平台问题
    示例中的 /dev/urandom/dev/random 仅适用于 Linux/Unix,Windows 需使用 BCryptGenRandomRtlGenRandom

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值