如何手动生成随机数

时间:2009-02-03 05:44:53

标签: random

我想手动生成随机数。我知道每种语言都有rand或随机函数,但我很想知道它是如何工作的。 有人有代码吗?

14 个答案:

答案 0 :(得分:11)

看看以下内容:

Random Number Generation

Linear Congruential Generator - 一种在Java中也使用的流行方法

List of Random Number Generators

这是另一个link,详细阐述了在Java的Random类中使用LCG

答案 1 :(得分:9)

POSIX.1-2001给出了以下rand()srand()实现的示例,当在两台不同的计算机上需要相同的序列时,这可能很有用。

static unsigned long next = 1;
/* RAND_MAX assumed to be 32767 */
int myrand(void) {
    next = next * 1103515245 + 12345;
    return((unsigned)(next/65536) % 32768);
}
void mysrand(unsigned seed) {
    next = seed;
}

答案 2 :(得分:6)

我认为你的意思是伪随机数。我所知道的最简单的一个(从旧机器上编写视频游戏)就是这样的:

种子=种子* 5 + 1;

每次调用随机数时都会执行此操作,然后使用所需的多个低位。 * 5 + 1具有很好的属性(IIRC),无论你看多少位,都可以在重复之前完成所有可能性。

当然,缺点是它的可预测性。但这在游戏中并不重要。对于各种各样的事情,我们抓住了疯狂的随机数字,你永远都不知道接下来会有多少数字。

并行完成这样的事情并结合结果。这是一个线性同余生成器。

答案 3 :(得分:5)

http://en.wikipedia.org/wiki/Random_number_generator

描述不同类型的随机数生成器及其创建方式。

答案 4 :(得分:5)

阿罗哈!

手动的意思是“不使用计算机”或“编写我自己的代码”?

如果它不使用电脑,你可以使用骰子,袋子里的数字和电视上看到的所有方法,当他们选择团队,赢得宾果系列等等。拉斯维加斯充满了过程中使用的这些方法(旨在为您提供不良赔率和投资回报率的游戏。您还可以获得精彩的兰德书并转向随机选择的页面:

http://www.amazon.com/Million-Random-Digits-Normal-Deviates/dp/0833030477

(另外,为了娱乐,请阅读评论)

要编写自己的代码,您需要考虑为什么不使用RNG提供的系统不够好。如果您使用的是现代操作系统,它将为用户程序提供RNG,这些程序应该足以满足您的应用程序。

如果你真的需要实现自己的,那么有很多可用的发电机。对于非安全性使用,您可以查看LFSR链,同余生成器等。无论您需要什么样的分布(统​​一,正常,指数等),您都应该能够找到算法描述和带有实现的库。

为了安全使用,您应该查看Yarrow / Fortuna,NIST SP 800-89指定的PRNG和RFC 4086等内容,以获得为PRNG提供信息所需的良好熵源。或者甚至更好,使用操作系统中 符合安全RNG要求的那个。

实施RNG可能是一项有趣的练习,但很少需要。除非是玩具应用,否则不要发明自己的算法。不要,重复不要为安全应用程序发明RNG(例如生成加密密钥),至少除非你做一些seripus阅读和调查。你会感谢我的(我希望)。

答案 5 :(得分:5)

    static void Main()
    {
        DateTime currentTime = DateTime.Now;

        int maxValue = 100;

        int hour = currentTime.Hour;
        int minute = currentTime.Minute;
        int second = currentTime.Second;
        int milisecond = currentTime.Millisecond;

        int randNum = (((hour + 1) * (minute + 1) * (second + 1) * milisecond) % maxValue);

        Console.WriteLine(randNum);

        Console.ReadLine();
    }

上面显示了一段非常简单的代码来生成随机数。它是一个用C#编写的控制台程序。如果你知道任何类型的基本编程,这应该是可以理解的,并且很容易转换成任何其他所需的语言。

DateTime只接受当前的日期和时间,大多数编程语言都有这样做的工具。

小时,分钟,秒和毫秒变量将日期时间值分解为其组成部分。我们只对这些部分感兴趣,所以可以忽略一天。同样,在大多数语言中,日期和时间通常表示为字符串。在.Net中,我们拥有可以轻松解析这些信息的工具。但是在大多数其他时间以字符串形式呈现的语言中,解析所需部分的字符串并将其转换为数字并不困难。这些设施通常以最古老的语言提供。

种子基本上给了我们一个总是在变化的起始数字。传统上,您只需将此数字乘以0到1之间的十进制值,这样可以减少该步骤。

upperRange定义最大值。因此,生成的数字永远不会超过此值。它也永远不会低于0.所以没有ngeatives。但如果你想要否定,你可以手动否定它。 (乘以-1)

实际变量randNum是什么包含您感兴趣的随机值。

技巧是在将种子除以上限后得到余数(模数)。余数总是小于除数,在这种情况下是100.简单的数学告诉你,你的余数不能超过除数。因此,如果你除以10,你就不能有一个大于10的余数。在这种情况下,这个简单的法则可以得到0到100之间的随机数。

console.writeline只是将其输出到屏幕上。

console.readline只是暂停程序,以便您可以看到它。

这是生成随机数的一段非常简单的代码。如果你每天在完全相同的工作间运行这个程序(但你必须在同一时,分,秒和毫秒),超过1天,你会开始一次又一次地生成相同的数字组额外的一天。这是因为它与时间紧密相关。那是发电机的分辨率。因此,如果您知道该程序的代码及其运行时间,您可以预测生成的数字,但这并不容易。这就是我使用毫秒的原因。使用秒或分钟只看我的意思。因此,您可以编写一个表格,显示1何时进入,0出现,2进入0时出现,依此类推。然后,您可以预测每秒的输出以及生成的数字范围。增加分辨率(通过增加更改的数字)越多,它就越难以获得可预测的模式所需的时间越长。这种方法足以满足大多数人的需要。

这是用于基本游戏的随机数生成的旧学校方式。它需要快速,简单。它是。这也突出了为什么,随机数字genaerators不是真正随机的,而是随机的psudo。

我希望这是对你的问题的合理答案。

答案 6 :(得分:3)

希望我不是多余的,因为我还没有阅读所有链接,但我相信你可以非常接近真正的随机生成器。如今系统往往如此复杂,以至于即使是最好的极客也需要花费大量时间才能理解内部发生的事情 :)。
只要打开你的思想并思考你是否可以监控一些全局系统属性,使用它播种...选择一个网络数据包(不适合你吗?)并从其内容中计算“某些东西”并使用它来播种......等等。
你可以通过所有这些提示设计出最符合你需求的产品;)

答案 7 :(得分:3)

Mersenne twister有一段很长的时间(2 ^ 19937-1)。

这是C ++中一个非常基本的实现:

struct MT{
    unsigned int *mt, k, g;
    ~MT(){ delete mt; }
    MT(unsigned int seed) : mt(new unsigned int[624]), k(0), g(0){
        for (int i=0; i<624; i++)
            mt[i]=!i?seed:(1812433253U*(mt[i-1]^(mt[i-1]>>30))+i);
    }
    unsigned int operator()(){
        unsigned int q=(mt[k]&0x80000000U)|(mt[(k+1)%624]&0x7fffffffU);
        mt[k]=mt[(k+397)%624]^(q>>1)^((q&1)?0x9908b0dfU:0);
        unsigned int y = mt[k];
        y ^= (y >> 11);
        y ^= (y << 7) & 0x9d2c5680U;
        y ^= (y << 15) & 0xefc60000U;
        y ^= (y >> 18);
        k = (k+1)%624;
        return y;
    }
};

答案 8 :(得分:3)

获取随机数的一个好方法是监控通过计算机麦克风传来的噪音环境水平。如果您可以获得一个驱动程序(或支持麦克风输入的语言)并将其转换为数字,那么您就可以了!

它也被研究过如何获得“真正的随机性” - 因为计算机只不过是二元机器,它们不能给我们“真正的随机性”。过了一会儿,序列将开始重复。寻求更好的随机数生成仍在继续,但他们表示,监控房间内的环境噪声水平是防止随机生成模式的一种好方法。

您可以查看this wiki article以获取有关随机数生成背后的科学的更多信息。

答案 9 :(得分:2)

如果您正在寻找关于随机数的理论处理,可能您可以查看计算机编程艺术的第2卷。它有一章专门介绍随机数。看看它是否有助于你。

答案 10 :(得分:2)

如果你想手动,硬编码,你自己的随机发生器,我不能给你效率,但是,我可以给你可靠性。我实际上决定用时间来编写一些代码,通过计算时间来测试计算机的处理速度,然后变成了我使用计数算法编写我自己的随机数生成器(计数是随机的)。请自己尝试一下,测试一个大型测试集中的数字分布。顺便说一句,这是用python编写的。

def count_in_time(n):
   import time
   count = 0
   start_time = time.clock()
   end_time = start_time + n
   while start_time < end_time:
       count += 1
       start_time += (time.clock() - start_time)
   return count


def generate_random(time_to_count, range_nums, rand_lst_size):
    randoms = []
    iterables = range(range_nums)
    count = 0
    for i in range(rand_lst_size):
        count += count_in_time(time_to_count)
        randoms.append(iterables[count%len(iterables)])
    return randoms

答案 11 :(得分:1)

这个document是伪随机数生成的非常好的写法,并且包含了许多例程(在C中)。它还讨论了对随机数发生器进行适当播种的必要性(见规则3)。对此特别有用的是使用/ dev / randon /(如果你在linux机器上)。

注意:本文档中包含的例程非常比Mersenne Twister编码更简单。另请参阅WELLRNG生成器,它应该具有更好的理论属性,作为MT的替代品。

答案 12 :(得分:1)

阅读随机数的rands书(monte carlo随机数书),其中的数字是随机生成的!我的祖父为兰德工作。

答案 13 :(得分:1)

大多数RNG(随机数发生器)需要进行少量初始化。这通常用于执行种子操作并存储种子值的结果以供以后使用。以下是我为游戏引擎编写的随机函数的播种方法示例:

    /// <summary>
    /// Initializes the number array from a seed provided by <paramref name="seed">seed</paramref>.
    /// </summary>
    /// <param name="seed">Unsigned integer value used to seed the number array.</param>
    private void Initialize(uint seed)
    {
        this.randBuf[0] = seed;
        for (uint i = 1; i < 100; i++)
        {
            this.randBuf[i] = (uint)(this.randBuf[i - 1] >> 1) + i;
        }
    }

这是从随机化类的构造函数中调用的。现在可以使用上述种子值滚动/计算实际随机数。这通常是应用实际随机化算法的地方。这是另一个例子:

    /// <summary>
    /// Refreshes the list of values in the random number array.
    /// </summary>
    private void Roll()
    {
        for (uint i = 0; i < 99; i++)
        {
            uint y = this.randBuf[i + 1] * 3794U;
            this.randBuf[i] = (((y >> 10) + this.randBuf[i]) ^ this.randBuf[(i + 399) % 100]) + i;
            if ((this.randBuf[i] % 2) == 1)
            {
                this.randBuf[i] = (this.randBuf[i + 1] << 21) ^ (this.randBuf[i + 1] * (this.randBuf[i + 1] & 30));
            }
        }
    }

现在存储滚动值以供稍后在此示例中使用,但这些数字也可以即时计算。预先计算的好处是性能略有提高。根据所使用的算法,可以直接返回滚动值,或者在代码请求时进行最后一分钟的计算。这是一个从预先滚动的值中获取的示例,并吐出一个非常好看的伪随机数:

    /// <summary>
    /// Retrieves a value from the random number array.
    /// </summary>
    /// <returns>A randomly generated unsigned integer</returns>
    private uint Random()
    {
        if (this.index == 0)
        {
            this.Roll();
        }

        uint y = this.randBuf[this.index];
        y = y ^ (y >> 11);
        y = y ^ ((y << 7) + 3794);
        y = y ^ ((y << 15) + 815);
        y = y ^ (y >> 18);
        this.index = (this.index + 1) % 100;
        return y;
    }