news 2026/8/20 21:56:41

为什么计算机里的“随机“几乎都是假的

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
为什么计算机里的“随机“几乎都是假的

这个系列一直在讲确定性——定点数、逐比特一致、全网同一个答案。今天岔开聊个看似无关、其实是一根线上的东西:随机数。因为你迟早会问,FPS 里霰弹枪的散射、暴击、掉落,这些"随机"怎么在所有客户端上还能算出一样的结果?答案是,计算机里的随机数压根就不是真随机,而这个"假",恰恰是我们求之不得的。

计算机没法凭空变出随机

先想一个最根本的问题:随机到底从哪来?

真正的随机,得来自物理世界某个本质上不可预测的过程——放射性原子什么时候衰变、电路里的热噪声、大气层的电磁扰动。这些东西背后没有公式,你没法算出来下一刻是多少,只能去测量

而计算机是什么?一台严格按指令执行的确定性机器。你给它同样的输入,它永远吐同样的输出——这本来就是我们指望它的地方,不然程序没法用了。可问题来了:一台"同样输入必然同样输出"的机器,你让它"给我一个不可预测的数",这本身就是矛盾的。它做的每一步都是可预测的,凭空变不出不可预测来。

所以计算机里绝大多数所谓的随机数,都不是真的随机,而是用一个确定的公式,算出一串看起来杂乱无章的数。这就是"伪随机"——pseudo,假的、伪装的。它看着随机,骨子里是被一个算法一步步推出来的,完全可复现。

伪随机长什么样:一个种子,一条链

理解伪随机,抓住两个词:种子(seed)和序列(sequence)。

伪随机数生成器(PRNG)干的事,是从一个初始值出发,反复套一个公式,每套一次得到一个新数,同时这个新数又变成下一次的输入。像滚雪球一样,一个推一个,滚出一长串数:

种子 → 公式 → 数1 → 公式 → 数2 → 公式 → 数3 → ... seed ↑______这个又喂回去当下一次的输入______↑

最经典的例子是线性同余(LCG),公式简单到你会怀疑它凭什么能"随机":

// 线性同余生成器,教科书级别的简单classLCG{ulongstate;publicLCG(ulongseed){state=seed;// 种子决定一切}publicuintNext(){// 乘一个大数、加一个数、取模——就这么三步state=state*6364136223846793005UL+1442695040888963407UL;return(uint)(state>>33);// 取高位,低位随机性差}}

就这么个"乘、加、截断"的公式,反复套,吐出来的数列却是杂乱无章、看不出规律的。你盯着数1、数2、数3……根本猜不到下一个是几——除非你知道种子和公式。

关键在种子。同一个种子,这条链每一步都完全一样,吐出的整串数分毫不差。换个种子,整条链就变成另一副样子。所以伪随机数不是"随机产生"的,是"由种子唯一确定"的一串数,只不过这串数的分布看起来足够均匀、足够杂乱,骗过了想找规律的眼睛。

vara=newLCG(12345);varb=newLCG(12345);// a 和 b 会吐出一模一样的序列,一个不差// a.Next() == b.Next(),永远成立

这就是"伪"的含义:它有随机的外表(数看起来乱),没有随机的内核(过程完全确定、可复现)。

那真随机在哪:得去"测"物理世界

伪随机之外,计算机确实也能搞到真随机,但代价是——它不能靠算,得靠采集物理世界的噪声

操作系统会去收集一堆本质上不可预测的物理事件:你敲键盘的精确时间间隔(精确到纳秒)、鼠标移动的微小抖动、硬盘寻道的时延、CPU 温度传感器的最低位、网卡收包的时间戳。这些东西背后是真实的物理混沌,攒到一起形成一个"熵池"(entropy pool)。Linux 上的/dev/random就是干这个的。现代 CPU 甚至内置了硬件随机数指令(比如 Intel 的 RDRAND),直接采电路热噪声。

但这些真随机有几个特点:慢(得等物理事件攒够熵)、不可复现(这才是重点,它就是要不可复现)、通常只用在最需要"绝对不能被预测"的地方——生成加密密钥、密码盐、安全 token。

也就是说,真随机是留给安全用的,那里"不可预测"是命根子。而日常你写的Random.Next()、游戏里的各种随机,几乎全是伪随机。这就回到标题:计算机里绝大多数随机数,都是伪随机。真随机是少数派,专供安全场景。

对游戏来说,"伪"不是缺陷,是刚需

讲到这你可能觉得,伪随机是个不得已的将就——真随机搞不到、太慢,只好用假的凑合。

反了。对我们做联机游戏的,伪随机的"可复现"恰恰是求之不得的宝贝。你顺着这个系列一路读下来,应该已经嗅到味道了:确定性。

想象霰弹枪开一枪,十几颗弹丸朝不同方向散射,每颗方向"随机"。在确定性同步的 FPS 里,这一枪的结果必须在所有客户端和服务器上完全一样——你屏幕上打空的那颗,队友屏幕上、服务器判定里,都得是打空的同一颗。要是各端各随机各的,你这打中了他那没打中,命中判定直接分裂,整局 desync。

伪随机怎么解决?所有端用同一个种子、同一个算法。种子一样,那条随机数链每一步都一样,散射的十几颗弹丸方向,红米、iPhone、服务器算出来一模一样。真随机在这里反而是灾难——它不可复现,各端各采各的物理噪声,结果必然对不上。

// 确定性同步里的随机:种子由全局状态派生,所有端一致classDeterministicRandom{ulongstate;// 种子通常来自:对局初始种子 + 当前逻辑帧号 + 某个事件序号// 这些在所有端都相同,所以派生出的 state 也相同publicDeterministicRandom(ulongsharedSeed){state=sharedSeed;}publicuintNext(){state=state*6364136223846793005UL+1442695040888963407UL;return(uint)(state>>33);}}

所以在确定性系统里,随机数生成器是被当作逻辑状态的一部分严格管理的:它的 state 要跟着走帧一起推进、要能打进快照、要在回放时精确恢复。它和角色位置、着地状态是一个待遇——都是必须逐比特一致的权威状态。

几条实战铁律

既然把随机数当逻辑状态管,前面整个系列讲定点数时那些洁癖,原样搬过来:

一,种子必须全端同源。别用本地时间、别用System.Random默认构造(它拿系统时间当种子,各端不一样)。种子要从对局共享的确定性状态派生——初始种子由服务器下发或大家约定,再混入逻辑帧号、事件序号这类全端一致的量。

二,算法要自己实现,别用系统库。平台自带的Random内部算法可能因运行时、版本、平台而异,不保证跨平台逐比特一致。这跟前面"别用Math.Sin,自己查表"是一个道理——凡是要全端一致的,底层实现必须攥在自己手里。自己写个 LCG 或者 xorshift,行为写死,谁都改不了。

三,输出走整数,别碰浮点。需要"0 到 1 的随机小数"时,别返回 float,返回定点数——拿整数随机值去除以范围,落到你的 Q 格式定点里。整个系列反复强调,一处浮点泄漏就满盘皆输,随机数这里也不例外。

四,谁调用、调几次,也得一致。这是最隐蔽的坑。随机数是一条有顺序的链,第 N 次调用拿到第 N 个数。如果某个端因为某种分支多调了一次Next(),它的链就错位了,从此之后全端随机数全对不上。所以不光种子要一致,消耗随机数的次数和顺序也必须在所有端严格一致。这条最容易翻车——一个客户端专属的表现逻辑不小心调了一下共享 RNG,整条链就歪了。表现层要随机,得用另一个独立的、不参与同步的 RNG,井水不犯河水。

收尾

怎么理解计算机里绝大多数随机数都是伪随机?一句话:计算机是确定性机器,同样输入必然同样输出,它凭空变不出真正的不可预测,只能用一个确定的公式从种子出发,算出一串看起来杂乱、实则完全可复现的数——这就是伪随机。真随机得靠采集物理世界的噪声,慢、不可复现,专留给加密这种"绝对不能被预测"的安全场景,是少数派。

而对做联机游戏的我们,伪随机的"可复现"不是缺陷是刚需:所有客户端和服务器用同一个种子、同一个算法,那条随机数链就在全端逐比特一致,霰弹散射、暴击、掉落,大家算出来分毫不差,命中判定才不会分裂。所以在确定性系统里,随机数生成器被当成逻辑状态的一部分严格管理——种子全端同源、算法自己实现、输出走定点、消耗顺序还得一致。

绕了一圈你会发现,这跟定点数、跟自己查三角函数表、跟重力常量烘成整数,是同一件事的不同侧面:确定性是从每一个"看起来该随机、该用系统库、该图省事"的角落,一点点守出来的。随机数只是又一个考验你守不守得住的地方。


版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/20 21:52:12

PoeCharm 上手指南:10 分钟把 Path of Building 变成全中文

PoeCharm 上手指南:10 分钟把 Path of Building 变成全中文 【免费下载链接】PoeCharm Path of Building Chinese version 项目地址: https://gitcode.com/gh_mirrors/po/PoeCharm 新赛季开服那晚,你兴冲冲打开 Path of Building(PoB&…

作者头像 李华
网站建设 2026/8/20 21:50:39

第一章:计算机系统概论

# 1.计算机系统的组成问题1:计算机的发展呈现出两种趋势 问题2:我国目前运算速度最快的超级计算机每秒可进行多少次浮点计算?(2021年408第12题) 2.计算机的硬件 2.1:冯 .诺依曼计算机 2.1.1:"存储程序”的概念 …

作者头像 李华
网站建设 2026/8/20 21:45:27

基于STM32的智能宠物喂食系统:从硬件设计到软件实现全解析

1. 项目背景与核心需求 对于许多养宠人士来说,定时、定量地给宠物喂食是一个不小的挑战。工作繁忙、临时出差或生活节奏不规律,都可能导致宠物错过饭点或饮食过量。传统的机械式喂食器功能单一,无法满足远程监控、按需投喂等智能化需求。因此…

作者头像 李华
网站建设 2026/8/20 21:42:42

5分钟上手SceneJS:零基础创建你的第一个WebGL 3D场景

5分钟上手SceneJS:零基础创建你的第一个WebGL 3D场景 【免费下载链接】scenejs An extensible WebGL-based 3D engine. This is an archived project. 项目地址: https://gitcode.com/gh_mirrors/sce/scenejs 想让浏览器里直接出现立体的3D画面,却…

作者头像 李华