您的位置:首页 > 编程语言 > C语言/C++

关于C++,Java和Python中的随机数生成法

2013-12-16 21:39 393 查看
首先我们来说说C++中的随机数生成:

我们知道在C++用函数rand()获取的是一个0 ~ RAND_MAX之间的一个随机数。其中RAND_MAX的值为32767。

首先我们来分析两个程序:

#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>

using namespace std;

int main()
{
    srand(time(0));
    for(int i=0;i<10;i++)
    {
        int t = rand();
        cout<<t<<endl;
    }
    return 0;
}


#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>

using namespace std;

int main()
{
    for(int i=0;i<10;i++)
    {
        srand(time(0));
        int t = rand();
        cout<<t<<endl;
    }
    return 0;
}


我们分别输出这两个程序的结果会发现,第一个程序结果为:



而第二个程序的结果是:



很明显,我们希望得到第一种结果。那么把srand(time(0))放到循环体内和放到循环体外有什么不同?

现在我来详细解释上面的结果。

我们首先要明确,对于函数srand(int num)和函数rand()它们是定义在头文件<stdlib.h>里的。

而srand(int num)函数的作用是散布num个随机数,当用rand()时,获取的是散布的这num个数中的任意一个。

rand()函数返回随机数序列中的下一个数,实际上srand(int num)函数是一个伪随机数序列,序列中的每一个数是由对其前面的数字进行复杂变换得到的。为了模仿真正的随机性,首先要调用srand()函数给序列设置一个种子。为了更好地满足随机性,使用了时间函数time(),以便取到一个随时间变化的值,使每次运行rand()函数时从srand()函数所得到的种子值不相同。伪随机数生成器将作为
"种子 "的数当作初始整数传给函数。这粒种子会使这个球(生成伪随机数)一直滚下去。

time(0)返回的是一个整数,这个整数的值等于1970年1月1日0时0分0秒至现在的秒数。所以这样随着时间的不同,生成的随机数的个数也不同。

至于第二个程序中所有的数字都相同,那是因为本身循环并不多,每个循环时间间隔很近,所以实际上time(0)的值都一样。这样相当于每次都是取随机序列中的第一个元素,那当然就一样了。

上面提到了生成的随机序列实际上是一个伪随机序列,其实后面的数是根据前面的数经过复杂的变换得到的。我们可以来看看srand(int num)函数的大体实现原理。

#include <iostream>
#include <string.h>
#include <time.h>
#include <stdio.h>

#define RANDOM_MAX 0x7FFFFFFF

using namespace std;

static long do_rand(unsigned long *value)
{
    /*
       这个算法保证所产生的值不会超过(2^31 - 1)
       
       这里(2^31 - 1)就是 0x7FFFFFFF。而 0x7FFFFFFF

       等于127773 * (7^5) + 2836,7^5 = 16807。

       整个算法是通过:t = (7^5 * t) mod (2^31 - 1)

       这个公式来计算随机值,并且把这次得到的值,作为

       下次计算的随机种子值。
    */
    long quotient, remainder, t;
    quotient = *value / 127773L;
    remainder = *value % 127773L;
    t = 16807L * remainder - 2836L * quotient;
    if (t <= 0)
        t += 0x7FFFFFFFL;
    return ((*value = t) % ((unsigned long)RANDOM_MAX + 1));
}

static unsigned long next = 1;

int rand(void)
{
    return do_rand(&next);
}

void srand(unsigned int seed)
{
    next = seed;
}

int main()
{
    srand((unsigned)(time(NULL)));
    for(int i=0;i<100; i++)
    {
        if(i % 10 == 0) puts("");
        printf("%d\t",rand()%99+1);
    }
    return 0;
}


经过上面的分析,就很容易获取一个0 ~ 1之间的一个随机小数。因为随机数中RAND_MAX最大,那么就很容易了:

double get_rand()
{
    return (double)rand() / (double)RAND_MAX;
}


在很多重要的算法中,我们没有用srand(int num)函数而直接用rand()来获取随机数,比如Miller素数测试,大数分解等等。这时实际上有一个默认的随机种子,这个随机序列是固定的。

那么,Java中的随机数又是怎么样的呢?

在java语言中生成随机数的方法有三种:

  1.通过System.currentTimeMillis()方法获取当前时间的毫秒数(long);
  2.通过Math.random()方法获取一个介于0到1之间的伪随机数;
  3.通过Random类获取随机数;

  在Random类中,使用了一个48位的种子数,并通过线性同于公式进行随机数的生成(参考《The Art of Computer Programming, Volume 2》书的3.2.1节。
  Random rand = new Random(System.currentTimeMillis());

在Java 中我们可以使用java.util.Random类来产生一个随机数发生器。它有两种形式的构造函数,分别是Random()和Random(long seed)。Random()使用当前时间即System.currentTimeMillis()作为发生器的种子,Random(long seed)使用指定的seed作为发生器的种子。

随机数发生器(Random)对象产生以后,

通过调用不同的method:nextInt(),nextLong(),nextFloat(),nextDouble()等获得不同类型随机数。

生成随机数

Random random = new Random();

Random random = new Random(100);//指定种子数100

random调用不同的方法,获得随机数。

import java.util.Random;

public class Srand {
		public static void main(String[] args){
				Random random = new Random(100);
				System.out.println(random.nextInt());
				System.out.println(random.nextFloat());
				System.out.println(random.nextBoolean());
		}
}


注意Java的Math类中也有一个random()方法,即Math.random()返回的是一个范围为[0.0,1.0)之间的小数。

在Java中,下面的代码表示生成10个0到49之间的随机数。

import java.util.Random;

public class Srand {
		public static void main(String[] args){
				Random random = new Random();
				for(int i=0;i<10;i++){
						System.out.println(random.nextInt(50));
				}
		}
}


在Python中,随机数的生成需要先导入random模块。

1.random.random()用于生成一个0到1的随机符小数: 0 <= n < 1.0

>>> import random
>>> random.random()
0.9658869832707923
>>>


2.random.uniform的函数原型为:random.uniform(a, b),用于生成一个指定范围内的随机符点数,两个参数一个是上限,一个是下限。如果a
> b,则生成的随机数n: a <= n <= b。如果 a<b, 则 b <= n <= a。

>>> random.uniform(1,10)
8.241539762435707
>>> random.uniform(10,1)
5.2752945576846075

>>>


3.random.randint()的函数原型为:random.randint(a, b),用于生成一个指定范围内的整数。其中参数a是下限,参数b是上限,生成的随机数n:
a <= n <= b

>>> random.randint(1,10)
8


4.random.randrange的函数原型为:random.randrange([start], stop[, step]),从指定范围内,按指定基数递增的集合中
获取一个随机数。如:random.randrange(10, 100, 2),结果相当于从[10, 12, 14, 16, ... 96, 98]序列中获取一个随机数。random.randrange(10,
100, 2)在结果上与random.choice(range(10, 100,2) 等效。

>>> random.randrange(0,100,2)
20


5.random.choice从序列中获取一个随机元素。其函数原型为:random.choice(sequence)。参数sequence表示一个有序类型。这里要说明 一下:sequence在python不是一种特定的类型,而是泛指一系列的类型。list,
tuple, 字符串都属于sequence。

>>> random.choice('ACdreamers')
'e'


6.random.shuffle的函数原型为:random.shuffle(x[, random]),用于将一个列表中的元素打乱。

>>> 
p = ['ACdreamers','Hello','World','NiHao']

>>> random.shuffle(p)

>>> print p
['World', 'Hello', 'ACdreamers', 'NiHao']

>>>


7.random.sample的函数原型为:random.sample(sequence, k),从指定序列中随机获取指定长度的片断。sample函数不会修改原有序列。
如果k大于sequence元素个数的话会报错。

>>> random.sample('ACdreamers',2)
['s', 'a']

>>>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: