今日思考:程序是如何实现随机的?以及什么是真随机和伪随机

今日思考:程序是如何实现随机的?以及什么是真随机和伪随机

1. 背景

今日神游,忽然沉思:随机是指现实生活中无规律,不可预测的事情,例如:抛硬币。那么在软件的世界里是如何实现这一物理现象的呢,遂做此探究。。。

什么是真随机和伪随机?

要弄明白程序是怎么实现随机的,首先得明白两个概念:

  1. 真随机
  2. 伪随机

2. 伪随机(Pseudo-Random)

2.1 定义

伪随机数(Pseudo-Random Number, PRN)是通过确定性算法生成的,看似随机但可预测的数列。这类随机数由数学公式计算得出,如果使用相同的初始种子(seed),则会生成相同的随机数序列。

2.2 伪随机的特点

  • 可复现性(Deterministic):相同的种子(seed)会生成相同的随机数序列。
  • 速度快(Fast):伪随机数使用数学公式生成,比真随机数快。
  • 周期性(Periodic):大多数伪随机数生成器最终会循环重复数值。

2.3 伪随机的常见算法

  1. 线性同余生成器(Linear Congruential Generator, LCG)
    ( X_{n+1} = (aX_n + c) \mod m )
    Java 的 Random 类使用 LCG 算法。

  2. 梅森旋转算法(Mersenne Twister, MT19937)
    Python 的 random 模块使用 MT19937,周期长((2^{19937}-1)),适用于科学计算和游戏随机数。

  3. XOR-Shift 算法
    java.util.concurrent.ThreadLocalRandom 采用此算法,适用于多线程环境。

  4. PCG(Permuted Congruential Generator)
    近年提出的高质量伪随机数算法,周期长且统计性质优良。

3. 真随机(True Random)

3.1 定义

真随机数(True Random Number, TRN)依赖物理现象产生,例如:

  • 电子噪声(Thermal Noise)
  • 放射性衰变(Radioactive Decay)
  • 用户输入时间间隔(Keyboard/Mouse Timing)
  • 硬盘磁头寻道时间(Disk Seek Time)
  • 网络封包延迟(Network Latency)

3.2 真随机的特点

  • 不可预测(Non-deterministic):无法通过数学公式计算得出。
  • 无周期性(Aperiodic):不会出现循环模式。
  • 通常较慢(Slower):依赖外部环境采样,比纯数学计算慢。
  • 可能受环境影响(Environmental Influence):例如噪声水平变化可能影响随机性。

3.3 常见的真随机数来源

  1. 硬件随机数生成器(Hardware RNG, HRNG)

    • Intel CPU 的 RDRAND 指令
    • AMD CPU 的 RDSEED 指令
    • 硬件安全模块(HSM, Hardware Security Module)
  2. 操作系统熵池(Entropy Pool)

    • Linux/dev/random(熵不足时会阻塞)、/dev/urandom(非阻塞)
    • WindowsCryptGenRandom API
  3. 用户行为

    • 采集用户鼠标移动、键盘输入时间间隔

4. 真随机 vs. 伪随机对比

特性 伪随机(Pseudo-Random) 真随机(True Random)
定义 计算机算法生成的可预测随机数 依赖物理现象生成的不可预测随机数
是否可复现
是否可预测
生成速度 较慢
是否有周期性
是否适用于密码学

程序是如何实现随机的?

上述概念我们其实可以得知,真随机一定要依赖现实世界的物理现象,因此,如果是纯软件实现的随机函数,都是伪随机。如果软件代码依赖了硬件(例如:硬件噪声)那么就可以实现真随机。

Java语言实现真随机和伪随机代码示例

伪随机

import java.util.Random;

public class PseudoRandomExample {
    public static void main(String[] args) {
        Random random = new Random(12345);  // 固定种子
        System.out.println(random.nextInt(100));  // 生成 0~99 之间的随机数
        System.out.println(random.nextInt(100));  
        System.out.println(random.nextInt(100));  
    }
}

输出(每次运行相同):

51
35
86

原理

Java 的 java.util.Random 类就是一个典型的伪随机数生成器(PRNG),它使用线性同余生成器(Linear Congruential Generator, LCG)算法。

线性同余算法(LCG)**

LCG 公式如下:
[
X_{n+1} = (aX_n + c) \mod m
]

  • (X_n) 是当前的随机数(或称“种子”)
  • (X_{n+1}) 是下一个随机数
  • (a)(乘数)、(c)(增量)、(m)(模数)是预定义的常数
  • Random 类的默认 seedSystem.nanoTime() ^ multiplier

Random 类的源码解析

Random 主要依赖 next() 方法,每次调用 nextInt()nextLong() 等方法时,都会基于 LCG 计算新的伪随机数。

private final AtomicLong seed;
private static final long MULTIPLIER = 0x5DEECE66DL;
private static final long ADDEND = 0xBL;
private static final long MASK = (1L << 48) - 1;
  • MULTIPLIER = 0x5DEECE66DL(乘数)
  • ADDEND = 0xBL(增量)
  • MASK = (1L << 48) - 1(模数,保证种子始终在 48 位范围)

核心的 next() 方法

protected int next(int bits) {
    long oldSeed, nextSeed;
    AtomicLong seed = this.seed;
    do {
        oldSeed = seed.get();
        nextSeed = (oldSeed * MULTIPLIER + ADDEND) & MASK;  // LCG 公式
    } while (!seed.compareAndSet(oldSeed, nextSeed));
    return (int) (nextSeed >>> (48 - bits));  // 取高 bits 位作为随机数
}
  • 采用 LCG 公式更新 seed
  • 使用 compareAndSet 保证线程安全
  • 右移 48-bits 以返回所需的位数

nextInt() 实现

public int nextInt() {
    return next(32);
}
  • nextInt() 直接调用 next(32),返回 32 位整数
  • next() 方法返回 48-bits,但 nextInt() 只取高 32 位

nextInt(int bound)(带上界)

public int nextInt(int bound) {
    if (bound <= 0)
        throw new IllegalArgumentException("bound must be positive");

    int r, m = bound - 1;
    if ((bound & m) == 0)  // 如果 bound 是 2 的幂
        return (int) ((bound * (long) next(31)) >> 31);

    do {
        r = next(31);
    } while (r - (r % bound) + m < 0);  // 确保均匀分布
    return r % bound;
}
  • 如果 bound 是 2 的幂,可以直接用位运算优化
  • 如果 bound 不是 2 的幂,用 拒绝采样法(Rejection Sampling) 处理边界情况,保证均匀分布

真随机

import java.security.SecureRandom;

public class TrueRandomExample {
    public static void main(String[] args) {
        SecureRandom secureRandom = new SecureRandom();
        System.out.println(secureRandom.nextInt(100));  // 生成 0~99 之间的真随机数
    }
}

问题: SecureRandom 真的是真随机吗?

其实,即便使用了SecureRandom , 也不一定是真随机,它的随机性取决于底层的实现。

SecureRandom 默认是加密安全的伪随机数生成器(CSPRNG)。它通常使用操作系统的安全随机源,如:

  • Linux/macOS/dev/urandom/dev/random
  • WindowsCryptGenRandom API

问题: 如何确保 SecureRandom 使用真随机

SecureRandom secureRandom = SecureRandom.getInstanceStrong();

强制使用真随机源:

SecureRandom secureRandom = SecureRandom.getInstance("NativePRNGBlocking");
  • NativePRNGBlocking 使用 /dev/random,但可能会阻塞。
  • NativePRNGNonBlocking 使用 /dev/urandom,速度快,但可能不是完全真随机。

最后

以上就是今日的一些思考,希望对你有帮助。

欢迎大家关注gzh: 加瓦点灯, 每天推送有意思的知识!

本文由mdnice多平台发布

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,607评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,239评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,960评论 0 355
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,750评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,764评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,604评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,347评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,253评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,702评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,893评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,015评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,734评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,352评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,934评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,052评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,216评论 3 371
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,969评论 2 355

推荐阅读更多精彩内容