【问题标题】:How does a random number generator work?随机数生成器如何工作?
【发布时间】:2010-12-15 12:52:59
【问题描述】:

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

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

【问题讨论】:

标签: random


【解决方案1】:

还有这个算法:

哦,更严重的是:

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

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

另请注意:

如果所有因rands 错误而导致结果受到质疑的科学论文都从图书馆的书架上消失,那么每个书架上都会有一个和你的拳头一样大的空隙。

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

【讨论】:

  • 这没有提供问题的答案。要批评或要求作者澄清,请在其帖子下方发表评论。
  • 埃尔克:现在好些了吗?
  • 随机性的问题在于你永远无法确定——但你可以通过统计测试(我记得我大学时代的卡方检验)将生成的数字传递并得到一个名为“置信度”。但是您可能需要连续 6 个以上的 9 才能得到否定结果:)
【解决方案2】:

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

Linear congruential generator 是最简单的示例之一(也可以实现)。当然,这些数字在你我看来是不可预测的,但它们实际上是在一个有限域内均匀分布的。

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

【讨论】:

  • \dev\random 更随机,您还可以附加一些东西来测量精确的空气温度或盖革计数器等更多随机性。
  • LCG 不一定会在 任何 有限域中产生输出,更不用说均匀间隔的数字了。
  • 感谢您的链接,我会再添加一个:en.wikipedia.org/wiki/Hardware_random_number_generator 我的意思是,实际上存在真正的 RNG。但是现在它们已经很少见了。
  • 我终于找到了一个同意计算机不能真正选择随机数的人。我喜欢这样想:计算机自己不做任何事情。事实上,可以说它们是宇宙中最愚蠢的东西。计算机所做的一切都是由人类编程的。因为我们有智力,所以我们可以选择看似随机的数字,但对于计算机来说并非如此。
【解决方案3】:

在过去,我制作它们的方法是从变化非常迅速的系统中获取一些价值,例如系统毫秒计时器。

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

随机数 = 整数(公式(计时器值))MOD 255

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

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


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

【讨论】:

  • 毫秒计时器不是一个快速变化的系统,对于大多数计算目的来说,它是一个半固定的数字,偶尔会改变一次。当它发生变化时,它会以完全可预测的方式发生变化。在最好的情况下,时间应该用作种子,并且只在一段时间内确保时间已经完全改变,然后再使用它。比计时器更好的是一个能够真正快速变化且非预测性的系统。
  • 好评。尝试在“更新”下提及此免责声明。
【解决方案4】:

我为 Java 找到了这个:

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

通过谷歌搜索how random functions work java

我确定答案是特定于语言的,但您可以尝试将我的 Google 查询更改为您选择的语言。

【讨论】:

    【解决方案5】:

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

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

    【讨论】:

      【解决方案6】:

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

      【讨论】:

        【解决方案7】:

        这是一些掷骰子的代码,它使用我自己开发的随机数生成器 这个 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#
        

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

        【讨论】:

          【解决方案8】:

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

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

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

          组合几个随机源(最简单的异或)组合它们的属性。

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

          【讨论】:

            【解决方案9】:

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2012-11-12
              • 1970-01-01
              • 2012-07-08
              • 2019-08-22
              • 1970-01-01
              • 2015-12-09
              • 1970-01-01
              相关资源
              最近更新 更多