随机数发生器如何工作?

时间:2009-11-11 16:24:34

标签: random

随机数发生器如何工作? (例如在C / C ++ Java中)

如何编写自己的随机数生成器? (例如在C / C ++ Java中)

9 个答案:

答案 0 :(得分:21)

还有这个算法:

enter image description here

哦,更严肃的是:

随机数生成器使用数学公式将数字集转移到另一个数字公式。例如,如果您使用常数N和另一个数字n_0,然后取n mod N(模运算符)的值,您将获得一个新数字{{1看起来与n_1无关。现在,使用n_0重复相同的过程,您将获得另一个号码。你在这里有一个看似随机数的(很糟糕)发生器。

请记住,我在这里描述的方法是一种玩具方法,不应该用于任何严肃的事情。但是,它确实说明了一般原则。

另请注意:

  

如果由于不良n_1而导致结果有疑问的所有科学论文都会从图书馆的书架上消失,那么每个书架上的间隙就会与你的拳头一样大。

(摘自Numerical recipes第7章)。对于任何使用随机数生成器进行任何认真工作的人来说,这是必读文本。

答案 1 :(得分:18)

要记住的一件事是没有“真正的”随机数生成器。他们只是生成看起来随机给我们凡人的数字。

最简单的一个例子(也是实施)是Linear congruential generator。当然,这些数字看起来对你和我来说都是不可预测的,但它们实际上是在有限的范围内均匀分布。

当然,有些生成器,如Blum Blum Shub,即使他将严格的数学技能和计算能力应用于任务,也无法预测局外人,但从根本上说,随机数生成器不是随机的;他们是有规律和可预测的。

答案 2 :(得分:5)

我过去如何制作它们的方法是从系统中获得一些真正快速变化的值,例如系统毫秒计时器。

接下来你需要做的是应用一些公式,从这个“输入”数字生成一个新数字并将其剪辑到你需要的范围,例如0..255:

random_number =整数(公式(计时器 - 值))MOD 255

这样,每次调用该函数时都会有一个新的“随机”数字。

示例公式函数可以是:
  公式(x)=((x XOR常数)+常数2)MOD范围
XOR曾经是我的最爱之一。


更新:我意识到这个公式非常糟糕,它会生成一组非常可预测的数字。此外,系统计时器太可预测为源。因此对于大多数应用来说,这还不够。如果您需要更好的随机性,请使用更多来源,而不仅仅是系统计时器和better formulas来组合它们。

答案 3 :(得分:3)

我发现这个用于Java:

http://www.javamex.com/tutorials/random_numbers/java_util_random_algorithm.shtml

通过Google搜索how random functions work java

我确定答案是针对特定语言的,但您可以尝试使用您选择的语言更改Google查询。

答案 4 :(得分:1)

有很多关于它们如何工作的信息......请参阅Konamiman的回答并稍微使用谷歌。

你为什么要写一个新的随机发生器?你可能不应该这样做......直到你需要一些非常特别的东西。例如,在游戏中,你可以使用产生“公平”随机值的shuffle bag - 查看this interesting question on SO
我在这里发布这个,因为当我第一次阅读它时,我真的很喜欢这个想法和实现:)

答案 5 :(得分:0)

这里有一些滚动骰子的代码,它使用我自己开发的随机数生成器 此RNG中的pad保持所有

中的15个十六进制值
 DIM pad(15) AS INTEGER
CLS
egg$ = "EFCDBA01457FA968"
  ghh$ = egg$
 nom% = 0
zen% = LEN(ghh$)
WHILE zen% > 0
opp$ = LEFT$(ghh$, 1)
eff% = ASC(opp$)
IF eff% >= 48 AND eff% <= 57 THEN eff% = eff% - 48 ELSE eff% = (eff% - 65) + 10
IF eff% > 15 THEN eff% = eff% - 32
pad(nom%) = eff%
nom% = nom% + 1
zen% = LEN(ghh$) - 1
ypp$ = RIGHT$(ghh$, zen%)
ghh$ = ypp$
WEND
sol& = 0
FOR zyx% = 0 TO 3
sol& = sol& * 16
sol& = sol& + pad(zyx%)
NEXT zyx%
sat% = sol& - 32768
RANDOMIZE sat%
FOR zyx% = 0 TO 15
PRINT HEX$(pad(zyx%));
NEXT zyx%
RANDOMIZE TIMER
respawn:
INPUT "sides per die"; die%
INPUT " number of dice"; dice%
INPUT "number to add to dice roll can be negative"; num%
INPUT "multiplier use 1 if so desired single precision floating point number"; g!
PRINT " hit any key to roll again with these values hit n for new values and q to quit"
PRINT " the number will be added or subtracted first before the multiplier takes effect"
reroll:
sum! = 0
FOR x% = 1 TO dice%
GOSUB rndmz
GOSUB demf
GOSUB drand
k% = INT(dr# * die%) + 1
sum! = sum! + k%
NEXT x%
sum! = (sum! + num) * g!
PRINT "you rolled a :"; sum!
i$ = ""
WHILE i$ = "": i$ = INKEY$: WEND
IF i$ = "n" THEN GOTO respawn
IF i$ = "q" THEN GOTO theend
GOTO reroll
theend:
SYSTEM
END
rndmz: rhet$ = ""
zum% = 0
FOR yxz% = 0 TO 15
FOR zyx% = 0 TO 15
IF zyx% MOD 3 = 0 THEN zum% = (zum% + pad(zyx%)) MOD 16
IF zyx% MOD 3 = 1 THEN zum% = (zum% + 16 - pad(zyx%)) MOD 16
IF zyx% MOD 3 = 2 THEN zum% = (zum% + INT(RND * 16)) MOD 16
NEXT zyx%
rhet$ = rhet$ + HEX$(zum%)
NEXT yxz%
ghh$ = rhet$
RETURN
demf: nom% = 0
zen% = LEN(ghh$)
WHILE zen% > 0
opp$ = LEFT$(ghh$, 1)
eff% = ASC(opp$)
IF eff% >= 48 AND eff% <= 57 THEN eff% = eff% - 48 ELSE eff% = (eff% - 65) + 10
IF eff% > 15 THEN eff% = eff% - 32
pad(nom%) = eff%
nom% = nom% + 1
zen% = LEN(ghh$) - 1
ypp$ = RIGHT$(ghh$, zen%)
ghh$ = ypp$
WEND
FOR zyx% = 0 TO 15
'PRINT HEX$(pad(zyx%));
NEXT zyx%
RETURN
drand: dr# = pad(0)
FOR eff% = 1 TO 15
dr# = dr# / 16
dr# = dr# + pad(eff%)
NEXT eff%
dr# = dr# / 16
RETURN
derf: a# = 1
x# = 1
b# = 1 / (2 ^ .5)
c# = .2500000000000011#
FOR u% = 1 TO 3
y# = a#
a# = (a# + b#) / 2
b# = (b# * y#) ^ .5
c# = c# - x# * (a# - y#) ^ 2
x# = 2 * x#
pi# = ((a# + b#) ^ 2) / (4 * c#)
PRINT pi#
NEXT u%
pi# = pi# + .000000000000015#
PRINT pi#

这里最后通过algorythm计算pi到几乎尽可能多的地方,抱歉它是用古老的基础语言编写的,这是我所知道的唯一编程语言,有可能把它移植到c ++或Java
只要仔细看看这个的逻辑,特别是关注启动或播种/初始化程序,这些程序必须使用,否则它将作为一个好的方法失败...这是我为游戏目的开发的,具有巨大的安全性并不像速度那么令人担忧......

答案 6 :(得分:0)

通过使用类似当前时钟时间的第五个小数的内容来播种这些类型的生成器也很常见,这对我们来说也是随机的。将来自几个混沌系统的输入加在一起,例如天气数据,股市数据,再次,使用模数,你有良好的种子数。

答案 7 :(得分:0)

取决于目标:速度 vs 质量 vs 安全。

速度和安全性:线性同余是直接的,不依赖于公共来源,密钥的隐私对于加密系统至关重要。

质量:random.org 是真正随机的来源,您每天可以免费获得大约 10000 个 16 位值。

组合多个随机源(最简单的 XOR)组合它们的属性。

因此,如果您还维护一个真正的随机数池,您就拥有速度、质量和安全性。

答案 8 :(得分:0)

https://github.com/fsssosei/Pure_PRNG/tree/main/src/prng_algorithms_package 下面是下面算法的实现: 逆同余生成器、LCG64_32_ext、XSM64、Ran64