随机数有多随机?_多么随机-程序员宅基地

技术标签: 编程珠玑  


作为一个常识,每个程序员在做入门学习时,都会被老师谆谆教导:我们用的编程语言中的随机函数,只能产生出伪随机数。它有它的内在规律,只能作为对显示世界的随机事件的近似模拟。接下来,我们通常会被传授随机种子的概念。以及用物理上更随机的量做种子。比如系统时间、两次敲击键盘的时间间隔、多次移动鼠标的偏移、甚至系统出错的出错信息码等等。

作为游戏数值策划,除了加减乘除,用的最多的数学概念恐怕就是随机数了。有经验的数值策划或许从他的前辈那得知计算机中程序产生的随机数并不太可靠;或者他本身就受过程序方面的训练。如果游戏项目更幸运一点,担当数值策划的他是一个数学爱好者,并读过诸如《计算机程序设计艺术》这样的技术书籍,那么事情会好的多。可惜大多数境遇下,策划们从不深究计算机随机数背后的细节,也不太关心所谓“伪”随机数究竟“伪”到什么程度。

最近几天,有测试人员向我抱怨,我们游戏中某些概率设定总感觉有点怪怪的。似乎跟文档上的不同。

这种抱怨并不少见,许多网络游戏玩家都在抱怨系统生成的随机数不太对劲。善良点的玩家会归咎到自己的 RP 上,阴谋论者则指责系统作弊。运营着的游戏背后,数值策划和程序员们有苦说不出。

有必要科普一些数学常识,也作为我周末读书的一些笔记。

鉴于我所接触过的多数游戏策划大多没有很高的数学素养(这里用于对比的参照物——我自己,在数学方面的修养已经够差了),下面不列公式,只列常识。如果涉及一些数学上的结论,也回避证明过程。

以扔硬币为例来看概率:

如果硬币本身没有问题,那么每次实验的结果,正面和反面的出现概率理应一致,都是 50% 。

btw ,如果碰巧连丢了 10 次都是正面的话,认为第 11 次出现反面的概率更高的读者可以不必看下去了。根据基本的概率理论,作为独立实验,相互间是不会造成概率影响的。无论前面出现多少次正面,下一次正面的概率依旧是 50% ,不会多也不会少。当然,如果是现实中出现这种情况,我会认为是道具本身出了问题,或许这个硬币两面都是正面。这样的话,第 11 次倒是极有可能再次出现正面。

对独立的随机事件的单次预测做不到准确,但却可以从统计上得到一个稳定的数值。我们知道,大量做丢硬币的实验 n 次。随着 n 的增大,出现正面和反面的次数会趋与一致。

OK ,以上都是作为一个游戏数值策划应该具有的常识。只是人们往往忽略了一点:若是正面和反面在多次实验中出现次数严格一致的话,又反过来是一件小概率事件。例如:丢一万次硬币,正好出现 5000 次正面的概率大概不会比你买彩票中个小奖的概率高多少。


补充:

在 10000 次一组的丢硬币的实验中,正好出现 5000 次正面的概率依旧是比所以其它情况概率更大一些的。其它情况可能是 10000 次 …… 5001 次、4999 次、4998 次 …… 甚至零次正面。

正好出现 5000 次正面有最大的可能性,但是绝对概率却不大(也不算太小)。

前段时间写过一篇 blog 谈到了用交换法洗牌 ,那篇文章中提及的一篇论文的结论谈到:

“当 N 大于等于 18 时,用这个方法洗牌后,居然恒等排列(identity permutation)是最有可能出现的。(所谓恒等排列大概是指第 n 张排在第 n 个位置)”

这句话很容易被人误解。概率最大并不等于很容易出现,正如 10000 次丢硬币刚好出现 5000 次正面不易出现一样。


如何看一个均匀分布的随机数发生器产生的数值到底随机不随机,简单的用统计产生出来的数字的分布是否接近均等是远远不够的。接下来介绍一下统计学中最著名的 χ 方检验。

假设我们投一个六面骰。每次 1 ~ 6 的点数出现的概率均为 1/6 。如果用计算机来模拟它,采用函数 random (1,6) 来产生一个 1 到 6 之间的随机整数。怎样判断产生的数字够不够随机呢?

我们可以投 n 次(n 很大,比如 n=10000 ),统计出每个点数出现的次数:Y1,Y2,Y3,Y4,Y5,Y6 。理想的次数则都应该接近于 p=n/6 次。

取 V=(Y1 - p)^2 / n + (Y2 - p)^2 / n + (Y3 - p)^2 / n + (Y4 - p)^2 / n + (Y5 - p)^2 / n + (Y6 - p)^2 / n

划简后 V=6/n * ( Y1 到 Y6 的平方和) - n

这个 V 即量化表示了这 n 次实验反应出来的数字随机性。当 V 过大时,骰子可能偏向某几个特定点数更多一些。而 V 过小的话,则可能是随机数发生器有一些明显的规律(事实上,所有伪随机数产生算法都是一定有规律的)。

我们现在需要知道的是,对于一个随机数列,什么样的 V 是比较合理的。对于用随机数做骰子的实验,V 的值也是随机的,当然不是均匀分布。实际上它符合 χ 方分布。如果我们投骰子用的随机数是真正的均匀分布的话,V 值出现特别小或特别大的概率都很小。

实际上,在这个六面骰的例子中,V 有 1% 的可能小于 0.5543 ,有 5% 的可能小于 1.1455 ,有 25% 的可能小于 2.675 ,有 50% 的可能小于 4.351 ,有 75% 的可能小于 6.626 ,有 95% 的可能小于 11.07 ,有 99% 的可能小于 15.09 。

我实验了 gcc 3.4.2 的 libc 中带的随机函数去模拟六面骰。做了五组实验,每组分别为 2000, 4000, 6000, 8000, 10000 次。得到的 V 的值分别为:

9.088 3.371 6.432 15.805 1.7204

注:我使用了系统时间做种子,每次做此实验都会得到不同结果,本质上这些值也是随机的。

每组次数不同是因为:伪随机数列往往具有一定的周期性,当不知道它的周期特性时,n 选的不合适可能导致多段非随机带有某中倾向性的区间相互抵消其影响。

我们再次分析上面得到的五个数据,若随机数真的随机,他们出现的概率大约落在这样五个区间75%~95%) ,(25%~50%) ,(50%~75%),(99%~100%),(5%~25%)

表现不太坏,但也不算好。尤其是第四组实验数据,V=15.805 ,这是个很大的值。因为 V 值本应有 99% 的概率小于 15.09 ,所以出现这个值的概率应该只有不到 1% 。当然这也可能是个巧合(1% 的事件发生并不算太奇怪)。我后来又反复取不同的 n 测算了几次,有一次 V 又小于了 0.55 ,这也不太正常(也只有不到 1% 的可能性)。

最后,我的结论是:我用的 gcc 这个版本的 rand 函数不算很好。至少不能应用于极端要求随机性的场合。它对大量模拟六面骰这件事情上做的不太成功。

ps. 关于 χ 方分布的选定的百分值,可以参考《计算机程序设计艺术 第二卷 半数值算法》的 P39 页。上面我摘取的第五行。因为这里六面骰的点数分布有五个自由度(第六种点数的出现次数可以用其它五种出现次数推算出来)。


前几天写过一篇 blog ,里面随手举了个例子:游戏设计人员设计了一个 10 万分之一的凋落率 。一个做策划的朋友在 gtalk 上问我,这并不是个复杂的问题呀。难道有什么玄机?

按这个朋友的思路,产生两次随机数就够了,一次 random(1,1000) 一次 random(1,100) ,只有两个数值都为 1 时,这个十万分之一个小概率事件才发生。

不错,理论上是这样,实际我们大多也这样的。而且很高兴看到,作为一个数值策划,他回避了直接用 random(1,100000) 。有编程常识的兄弟们都知道,大多数语言提供的标准数学函数库中不提供十万分之一级别精度的随机函数。

但是精度问题依然存在。我反过来问如果产生一个十万分之七的随机数时,他出现了一点小失误:random(1,100) * random(1,1000) <=7 是不对的。当然这个小错误很容易被修正。

实际应用中,更为正确的做法是回避直接使用高分辨率的随机数列。因为通常所用的线形同余序列产生的伪随机数列都不适用(道理很简单,每个随机数的精度要求提高意味着伪随机数列的周期变短,过短的周期性必然带来随机性的丧失)。如果真的有这类需求,我们应该让程序员去专门写一个了。

不光是这种超高精度随机数的需求应该尽量被回避。单次随机量的自由度也最好被限制。计算机模拟丢硬币总比模拟投六面骰看起来要真实一些。而模拟六面骰又好过二十面。用固定面数的骰子模拟出来,也比数值设定时八卦一个百分比概率要强。

原因并非完全源于它们需要的精度不同。更重要的是自由度小一些的随机量,更容易被统计方法检验是否合理。一旦程序产生的伪随机数随机性被检验出来不太好,我们总有机会去尝试一个更好的,不是吗?

最后推荐一个随机数发生器:http://www.agner.org/random/

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/memray/article/details/8933134

智能推荐

10分钟搭建ubuntu+nodejs+pm2自动部署+nginx+永久免费SSL证书+mongodb自动部署环境-程序员宅基地

文章浏览阅读273次。如果你对nodejskoa2vuejs等感兴趣,请加QQ群:732189938 或者直接点击链接加入群聊【Node.js/Koa2/vuejs】:https://jq.qq.com/?_wv=1027&k...准备全新ubuntu请先执行以下命令安装常用工具sudo apt-get install git vim wget ..._pm2 安全证书

HTML入门(三)注释及head标签_head如何注释-程序员宅基地

文章浏览阅读2.9k次,点赞2次,收藏3次。前言 前面我们通过记事本以及开发工具HBuilder了解了一个基本的html文件的编写以及运行方法,接下来我们深入其中,了解每一个标签的使用,以及它们的特点。特别的:本系列一切遵循HTML5标准,至于为什么把head标签拿出来,是因为以后的css,js等引用均写在其中,并且其字符集的设置尤为关键,一个不小心就会乱码。方法1.html注释我们知道,任何一门语言都有它自己..._head如何注释

机器学习入门与Python实战核心工具篇:pip源、python、anaconda、工具包(完整版)_机器学习pip-程序员宅基地

文章浏览阅读884次,点赞3次,收藏7次。一句话介绍:为了进行机器学习快速开发,我们将使用python语言编程、anaconda管理不同的项目环境、jupyter notebook进行断点高效调试、不同的工具包快速搭建模型。pip国内镜像源链接阿里云 http://mirrors.aliyun.com/pypi/simple/ 中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/ 豆瓣(douban) http://pypi.douban.com/simple/ 清华大学 https://py_机器学习pip

小程序webview链接公众号授权网页-程序员宅基地

文章浏览阅读9.6k次。小程序使用公众号授权页面_小程序webview链接公众号授权网页

临床预测模型-程序员宅基地

文章浏览阅读93次。想请教一下各位大佬,能建立阴虚血瘀型患者的临床预测模型吗。

使用灰狼算法优化的LSTM实现数据回归预测_优化lstm预测-程序员宅基地

文章浏览阅读157次。然后,我们定义了灰狼算法的参数,并初始化了灰狼的位置。在优化过程中,我们通过更新灰狼的位置和LSTM网络的参数来逐步优化预测结果。通过灰狼算法的优化,我们可以提高LSTM网络的性能和准确性,从而得到更好的数据预测结果。灰狼算法利用灰狼的行为模式来搜索最优解,结合LSTM网络的强大建模能力,可以更好地捕捉时间序列数据中的关键特征和模式。需要注意的是,上述代码中的部分变量需要根据具体问题进行设置和调整,例如数据的维度、LSTM网络的层数、灰狼算法的参数等。灰狼算法是一种群体智能算法,模拟了灰狼的群体行为。_优化lstm预测

随便推点

如何让谷歌搜索到自己在GitHub上的博客,好用!_谷歌收录 github博客-程序员宅基地

文章浏览阅读359次,点赞12次,收藏6次。看着两个链接,好用!_谷歌收录 github博客

树莓派3B CSI摄像头配置_csi摄像头连接树莓派-程序员宅基地

文章浏览阅读719次,点赞3次,收藏4次。树莓派3B CSI摄像头配置_csi摄像头连接树莓派

关于模型预测结果好坏的几个评价指标-程序员宅基地

文章浏览阅读2.4w次,点赞17次,收藏147次。总第241篇/张俊红在人工智能算法大数据时代,会有各种各样的预测模型,那怎么来评判一个预测模型的准确度呢?这一篇就来聊聊常用的一些评价指标。所谓的预测准确度其实就是预测值和实际值之间的相..._预测模型评价指标

SVG元素缩放的问题_html svg只能等比例缩放吗-程序员宅基地

文章浏览阅读1.2w次。SVG元素缩放的问题页面里嵌入的SVG元素,有时候需要对其进行缩放。在网上研究了一下,SVG元素的缩放有两种方法。 一种是使用SVG元素的viewBox属性(参考http://www.douban.com/note/271260021/)viewBox的使用方法如下:http://www.w3.org/2000/svg"version="1.1"> 这_html svg只能等比例缩放吗

数组,数组名,引用数组,数组引用,数组拷贝_引用传数组名-程序员宅基地

文章浏览阅读1.1k次,点赞2次,收藏4次。本系列博客只为平时在C++学习过程中遇到的一些比较杂乱的问题,希望能够与大家慢慢积累,让基础更加扎实!1.数组,数组名,引用数组,数组引用,数组拷贝引用:首先理解引用。引用就是一个别名,不分配内存空间,是间接访问的一种方式。我们可以很直接联想到指针,但是指针不一样,指针本身就是一个对象,是有分配内存空间的。数组与数组名:数组,大家都很熟悉,就是一个固定大小的容器。对于数组名..._引用传数组名

五指CMS copyfrom.php SQL注入漏洞复现(CVE-2023-52064)-程序员宅基地

文章浏览阅读452次,点赞3次,收藏2次。Wuzhicms 内容管理系统的/core/admin/copyfrom.php $keywords参数存在SQL注入漏洞,经过身份验证的攻击者可通过该漏洞获取数据库中的信息之外,甚至在高权限的情况可向服务器中写入木马,进一步获取服务器系统权限。_五指cms copyfrom.php

推荐文章

热门文章

相关标签