大佬们,生成随机数这样加多个函数有意义吗

2023-12-25 20:33:59 +08:00
 way2create

场景

单机的小项目,后台内部用,不需要开放,要求就是给数据生成一个 8 位纯数字的序列号,本身不需要包含什么含义,只要能通过序列号找到这个数据,不重复。 数据量也很小,可能一年都不会超过 1000 个,所以我在数据库设置了唯一索引后直接就用生成随机数的函数了,如下:

mt_rand(10000000,99999999);

但刚好我同事看到,说建议我改成:

str_shuffle(mt_rand(10000000,99999999));

说这样更好,更随机,重复的概率更低。 感觉不太对劲,我个人感觉这样不会更随机吧?但我对函数的底层的东西没什么深入研究。

我 google 了一下,但我可能搜索姿势不太对没找到完全相同的场景,但我看到有类似的代码,答案有提到说 str_shuffle 不会增加额外的熵。

是不是就是意思这样做不会增加随机性也不会让重复的概率变低?

所以发这个贴子来问问大家,谢谢!如果有相关的资料可以让我加深理解就更好了!

1999 次点击
所在节点    程序员
27 条回复
june4
2023-12-25 20:38:05 +08:00
你不是应该要你同事给出这样更随机的证明吗
infun
2023-12-25 20:41:13 +08:00
分别调用个十万次看看先?
sadfQED2
2023-12-25 20:41:46 +08:00
啊?如果随机出来的数是 1000000 ,你 str_shuffle 之后变成 00000001 ,这不会出问题吗?

我没看过 mt_rand 的实现方法,但是如果每个数出现概率一样的话,你再加个打乱逻辑的话,纯粹脱了裤子放屁。

如果 mt_rand 每个数出现概率不一样的话,那这样打乱一下有意义
maggch97
2023-12-25 20:42:59 +08:00
你要做的是处理出现重复数字之后的异常处理,这个概率并不低。
dobelee
2023-12-25 20:44:11 +08:00
觉得随机买一张彩票概率太低,于是买了十张,手动混一混,再从里面选一张。
imdong
2023-12-25 20:44:31 +08:00
对于你描述的场景,二者没法证明有实质意义的区别。

如果真的需要安全的随机数,我觉得你们需要的不是更随机的随机数,而是更可控的随机数。

说白了,就是需要一个看起来是随机但实际上不是随机的随机数。
passive
2023-12-25 20:44:51 +08:00
两个均匀分布相加或者嵌套不再是均匀分布,无数个均匀分布相加或者嵌套最后会变成正态分布🐶
way2create
2023-12-25 20:47:27 +08:00
@maggch97 这个有做的 而且实际上并不是单纯 8 位 还有别的 这里省略了 就是好奇问的问题
way2create
2023-12-25 20:49:02 +08:00
@sadfQED2 谢谢,你说的很有道理,变成 00000001 从我给的代码来看也是个问题,不过还好实际的场景不在乎这个,我这里只是用例子来表达我要问的问题,是我的疏忽。
maggch97
2023-12-25 20:51:42 +08:00
@way2create 做了兜底就别管你同事说啥了。没有什么恶意,但是我不觉得写 PHP 的对随机数生成有什么深入的理解
way2create
2023-12-25 20:54:35 +08:00
@way2create 我是不深入 他我不知道 就是因为这事产生的疑问 水平有限所以来问问
geelaw
2023-12-25 21:00:57 +08:00
目测 mt_rand(10000000, 99999999) 的输出一定以 1 开始,那自然不是均匀随机的 8 位纯数字序列号(当然 MT 本身就不够随机,但这是另一码事儿了),毕竟均匀随机的 8 位纯数字序列号以 1/10 的概率以 0 开始。

对这个分布套上 str_shuffle 是会“变得更随机”(增加分布的熵)的,但 str_shuffle 之后得到的依然不是八位纯数字序列号,因为它不可能是 00000000 ,而真正随机的以 10^(-8) 的概率出现 00000000 。

如楼上 @maggch97 所说,这个数据范围出现碰撞的概率不小。最简单的做法是:预先生成好 0 到 99999999 的一个置换(打乱一个 0 到 99999999 的列表,并存下来),然后每次需要的时候取用。
kingjpa
2023-12-25 21:08:55 +08:00
time().mt_rand(1111,9999)
clemente
2023-12-25 21:12:53 +08:00
mt_rand(10000000, 99999999) 已经足够随机,并且使用 str_shuffle 不会增加其随机性。

mt_rand 函数使用 Mersenne Twister 算法生成伪随机数,而且已经足够随机,无需额外的操作。在你的用例中,使用 str_shuffle 并不会增加数字的随机性,因为它是为字符串设计的。
way2create
2023-12-25 21:35:31 +08:00
@geelaw 谢谢你的回答 因为我们项目数据量实在是太小了 所以我只做了简单的随机数+万一重复的错误处理 感谢你提的方案 不过其实代码跟实际需求有点不一样 我省略了主要是想问标题本身的
way2create
2023-12-25 21:50:41 +08:00
@clemente 谢谢 我 Google 的时候就是有看到类似的答案 想着来 V2 确认一下的
newaccount
2023-12-26 09:17:39 +08:00
随机数要保证结果的均匀分布,str_shuffle 这东西不像是做这个用的,理论上讲,加了之后是负优化

随机数算法的测试,印象中是在 《 delphi 算法与数据结构》这本书上看到过,通过撒点图形看是否存在不正常的 pattern ?年头有点久,记不太清了

算法是通用的,你看看别的语言实现的随机数算法评估方法
CodeCodeStudy
2023-12-26 09:18:20 +08:00
用 random_int 这个函数

random_int(int $min, int $max): int
way2create
2023-12-26 09:25:13 +08:00
@newaccount 好的谢谢我去搜搜看 其实我也就是单纯好奇他加这个函数 除了表面上的打乱 究竟是真的优化还是多此一举负优化
afeiche
2023-12-26 09:28:05 +08:00
我感觉需求和实现不匹配,需求是要唯一,而实现是生成随机数,但是用 rand 应该是会有一定的重复概率,不如按顺序生成靠谱一点

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1003355

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX