读书人

使用Random的两个误区,兼散分帖~解决思

发布时间: 2012-01-02 22:40:04 作者: rapoo

使用Random的两个误区,兼散分帖~
昨天一朋友问了下我关于他写的一段程序的错误.
其中有一个问题就是关于随机数的.他的代码如下(C++代码).

C/C++ code
for (int i =0;i< n;++i){    srand((unsigned)time( NULL ));     int r = rand()%100;    cout << r << ",";}

这里很明显他是想输出一串小于100的随机的数列.可是运行结果输出的却是类似
97,97,97,97,....97,30,30,30,30,30,30,30,30,30,30,30,30,....,27,27,27,27,27,27,....
的序列.很明显这样完全看不出有任何的随机性.这是由于他对C的rand函数不理解导致
的错误用法.而这两天逛C#区我也同样看到了几个类似的错误用法(C和C#的rand从大体
的原理上差不多).想想自己初学的时候类似的错误犯得也不少.所以自己下去查了写资料
总结了在随机数使用上的一些错误的用法.希望能对初学者有所帮助.

先来说说随机数算法的实现.借用C数值算法里的一句话:利用计算机,这种人类所设计的
各种机器中最精确,最能做出确切判断的机器,来产生"随机数",这看上去有些自相矛盾.甚至在
概念上是讲不通的.任何程序必将产生完全可以预计的结果.因而不是真正的"随机数".

现在各种语言中的随机数产生函数所产生的"随机数",实际上被称之为"伪随机数".可以将
整个随机数函数看做这样一个表达式:

A = R(s)

其中R是随机函数,s是种子.A是一个数列.即对于任意一个种子s,经过R的计算后,总有一个确定
的数列A与之对应.而当在C#里调用var rnd = new Random (s)或在C里调用srand(s)实质上
所做工作之一就是设定这个种子.而rnd.Next();或rand()只不过是在A上取下一个元素而已.当然实
际的实现不可能事先计算一个数列A,所以rand()相当于由s计算出下一个数字s',然后将s'作为新
的种子赋值给s,最后将s'作为结果返回.

接下来就是两种常见的错误用法了:
C# code
for (int i=0;i<n;++i){    var rnd = new Random (s);//s是实先确定的一个数字    Console.Write ("{0},",rnd.Next());}

这样使用随机数产生器只会产生一个固定的常数N.
因为每次都用同一个种子初始化了随机数产生器后调用了Next().
所取得的都是数列A上的第一个元素.而这个元素的值肯定是固定
的(当然N取什么值要看随机函数的实现而定).

而第二种情况就更常见了:
C# code
for (int i=0;i<n;++i){    var rnd = new Random ();//用系统时间作为种子    Console.Write ("{0},",rnd.Next());}


这样调用应该是希望通过时间的不同来达到随机的效果;但是得到的结果就和我那位朋友一样.会是形似
97,97,97,97,....97,30,30,30,30,30,30,30,30,30,30,30,30,....,27,27,27,27,27,27,....
的一串数列.这是因为Windows系统时钟的更新频率大概在10ms左右.而这个for循环的执行显然要快
得多.于是在一段执行时间内Environment.TickCount (Random的默认种子)或是C的time函数返回的
都是同一个值.从而导致rnd.Next在一段时间内返回一个常数.

所以正确的用法应该将随机数产生器的初始化移出循环:
C# code
var rnd = new Random ();//用系统时间作为种子for (int i=0;i<n;++i){    Console.Write ("{0},",rnd.Next());}


就我个人习惯来说.在一个经常用到随机数的程序中,我会在Main中就初始化一个全局的随机数产生器,在
之后要用到随机数的地方就直接调用Next,而不用每次都构造一个Random.

[解决办法]
犯过类似的错误):解决方法与楼上同
[解决办法]
看看
[解决办法]

[解决办法]
up
[解决办法]
一般如果要输出的随机数不重复,都把生成好了的,放到一个列表中
Random rnd = new Random();
比如说输出1-100不重复的随机数
C# code
List<int> list=new List<int>();for(int i=0;i<100;i++){   int value=rnd.Next(1, 101);   while(list.Contains(value)){     value=rnd.Next(1, 101);}list.Add(value);}
[解决办法]
搂主没错,的确是这样的,刚回了一个这样的贴,见下面贴:
http://topic.csdn.net/u/20081227/11/d47c3275-0e5d-4543-8e5a-0399a4c37880.html
6楼代码也是这样做的
[解决办法]
Mark
[解决办法]
写的不错,是这样
------解决方案--------------------


这个帖子一定要顶起来
[解决办法]
学习..UP
[解决办法]

[解决办法]
恩。
[解决办法]
C#里的随机数算法用的就是高德纳在《计算机程序设计艺术》里写的算法。
我以前遇到这个问题就是查了原版书才发现的。

[解决办法]
呵呵说得好。还有什么技巧啊
[解决办法]
学习了
[解决办法]
确实是这样的
[解决办法]
学习ing
还学习楼主分享精神!
[解决办法]
学习下
[解决办法]
路过,,把Random类代码帖出来…………

C# code
/* * Copyright (c) 2008 Microsoft::Tsorgy.Utils, Reserved. *  * Filename:    @(#)Random.cs * Create by:   TsOrgY * Email:       tsorgy@gmail.com * Date:        2008/12/27 15:01:40 *  * Classname:   Random * Description: 一种能够产生满足某些随机性统计要求的数字序列的设备. *               */using System;using System.Runtime.InteropServices;namespace Tsorgy.Utils {    /// <summary>    /// 表示伪随机数生成器,一种能够产生满足某些随机性统计要求的数字序列的设备.    /// </summary>    [Serializable]    [ComVisible(true)]    public class Random {        private int inext;        private int inextp;        private const int MBIG = 0x7fffffff;        private const int MSEED = 0x9a4ec86;        private const int MZ = 0;        private int[] SeedArray;        /// <summary>        /// 使用与时间相关的默认种子值,初始化 Random 类的新实例.        /// </summary>        public Random()            : this(Environment.TickCount) {        }        /// <summary>        /// 使用指定的种子值初始化 System.Random 类的新实例.        /// </summary>        /// <param name="Seed">用来计算伪随机数序列起始值的数字。如果指定的是负数,则使用其绝对值。</param>        /// <exception cref="System.OverflowException">Seed 为 System.Int32.MinValue,在计算其绝对值时会导致溢出。</exception>        public Random(int Seed) {            this.SeedArray = new int[0x38];            int num2 = 0x9a4ec86 - Math.Abs(Seed);            this.SeedArray[0x37] = num2;            int num3 = 1;            for (int i = 1; i < 0x37; i++) {                int index = (0x15 * i) % 0x37;                this.SeedArray[index] = num3;                num3 = num2 - num3;                if (num3 < 0) {                    num3 += 0x7fffffff;                }                num2 = this.SeedArray[index];            }            for (int j = 1; j < 5; j++) {                for (int k = 1; k < 0x38; k++) {                    this.SeedArray[k] -= this.SeedArray[1 + ((k + 30) % 0x37)];                    if (this.SeedArray[k] < 0) {                        this.SeedArray[k] += 0x7fffffff;                    }                }            }            this.inext = 0;            this.inextp = 0x15;            Seed = 1;        }        private double GetSampleForLargeRange() {            int num = this.InternalSample();            if ((((this.InternalSample() % 2) == 0) ? 1 : 0) != 0) {                num = -num;            }            double num2 = num;            num2 += 2147483646.0;            return (num2 / 4294967293);        }        private int InternalSample() {            int inext = this.inext;            int inextp = this.inextp;            if (++inext >= 0x38) {                inext = 1;            }            if (++inextp >= 0x38) {                inextp = 1;            }            int num = this.SeedArray[inext] - this.SeedArray[inextp];            if (num < 0) {                num += 0x7fffffff;            }            this.SeedArray[inext] = num;            this.inext = inext;            this.inextp = inextp;            return num;        }        /// <summary>        /// 返回非负随机数.        /// </summary>        /// <returns>大于或等于零且小于 System.Int32.MaxValue 的 32 位带符号整数。</returns>        public virtual int Next() {            return this.InternalSample();        }        /// <summary>        /// 返回一个小于所指定最大值的非负随机数.        /// </summary>        /// <param name="maxValue">要生成的随机数的上界(随机数不能取该上界值)。maxValue 必须大于或等于零。</param>        /// <returns>大于或等于零且小于 maxValue 的 32 位带符号整数,即:返回的值范围包括零但不包括 maxValue。</returns>        /// <exception cref="System.ArgumentOutOfRangeException">maxValue 小于零。</exception>        public virtual int Next(int maxValue) {            if (maxValue < 0) {                throw new ArgumentOutOfRangeException("maxValue", string.Format("'{0}' must be greater than zero.", maxValue));            }            return (int) (this.Sample() * maxValue);        }        /// <summary>        /// 返回一个指定范围内的随机数.        /// </summary>        /// <param name="minValue">返回的随机数的下界(随机数可取该下界值)。</param>        /// <param name="maxValue">返回的随机数的上界(随机数不能取该上界值)。maxValue 必须大于或等于 minValue。</param>        /// <returns>一个大于或等于 minValue 且小于 maxValue 的 32 位带符号整数,即:返回的值范围包括 minValue 但不包括 maxValue。如果minValue 等于 maxValue,则返回 minValue。</returns>        /// <exception cref="System.ArgumentOutOfRangeException">minValue 大于 maxValue。</exception>        public virtual int Next(int minValue, int maxValue) {            if (minValue > maxValue) {                throw new ArgumentOutOfRangeException("minValue", string.Format("'{0}' cannot be greater than {1}.", minValue, maxValue));            }            long num = maxValue - minValue;            if (num <= 0x7fffffffL) {                return (((int) (this.Sample() * num)) + minValue);            }            return (((int) ((long) (this.GetSampleForLargeRange() * num))) + minValue);        }        /// <summary>        /// 用随机数填充指定字节数组的元素.        /// </summary>        /// <param name="buffer">包含随机数的字节数组。</param>        /// <exception cref="System.ArgumentNullException">buffer 为 null。</exception>        public virtual void NextBytes(byte[] buffer) {            if (buffer == null) {                throw new ArgumentNullException("buffer");            }            for (int i = 0; i < buffer.Length; i++) {                buffer[i] = (byte) (this.InternalSample() % 0x100);            }        }        /// <summary>        /// 返回一个介于 0.0 和 1.0 之间的随机数.        /// </summary>        /// <returns>大于或等于 0.0 而小于 1.0 的双精度浮点数字。</returns>        public virtual double NextDouble() {            return this.Sample();        }        /// <summary>        /// 返回一个介于 0.0 和 1.0 之间的随机数.        /// </summary>        /// <returns>大于或等于 0.0 而小于 1.0 的双精度浮点数字。</returns>        protected virtual double Sample() {            return (this.InternalSample() * 4.6566128752457969E-10);        }    }} 


[解决办法]
学习,以前也经常犯这样的错误
[解决办法]
总结的挺好
[解决办法]
经常看到这样的错误
[解决办法]
路过.
[解决办法]
Random ra = new Random();
MessageBox.Show("您今天的幸运数字是\n " + ra.Next(0, 99), "幸运数字", MessageBoxButtons.OK, MessageBoxIcon.Information);

哈哈
[解决办法]
学到不少
谢谢了
[解决办法]
非常好
[解决办法]
en
[解决办法]
MARKED
[解决办法]
up
[解决办法]
发布出去帖子。
[解决办法]
要定义种子啊

最常用的是用时间ticket做种
[解决办法]
fen,up
[解决办法]
mark
[解决办法]
不错~!

[解决办法]
谢谢~
[解决办法]
学习
[解决办法]
研究
[解决办法]
UP
[解决办法]
学习
[解决办法]
学习!
[解决办法]
真的不错唉。学习了。
[解决办法]

探讨
C#里的随机数算法用的就是高德纳在《计算机程序设计艺术》里写的算法。
我以前遇到这个问题就是查了原版书才发现的。

[解决办法]
很好很好
[解决办法]
我也要分啊
[解决办法]
说白了,还是伪随机
[解决办法]
不错,推荐一下
[解决办法]
UP
[解决办法]
学习,顶!
[解决办法]
顶楼主和20楼

楼主的问题没犯过 但是的确有用
20楼的是好东西

一个游戏没有随机函数很难做 有了随机函数其实就会做一些简单的游戏了
所有游戏都带赌
[解决办法]
学习,顶!
[解决办法]
学习!
------解决方案--------------------


慢慢学习

PS:
我的目标是 ---->

^_^

[解决办法]
学习了!
[解决办法]
...
[解决办法]
sdfsdfsdfsdfdsfdssdfsdf
[解决办法]
up

探讨
学习了!

[解决办法]
up
[解决办法]
不错。
[解决办法]
遇到过
[解决办法]
现实,顶分
[解决办法]
mark
[解决办法]
不错 学习
[解决办法]
var rnd = new Random ();//用系统时间作为种子
for (int i=0;i<n;++i)
{
Console.Write ("{0},",rnd.Next());
}
[解决办法]
恩,必须下种子才正确的。
[解决办法]
没犯过这种错误,帮顶
[解决办法]
看看!!

[解决办法]
挺喜欢这样的总结~
[解决办法]
mark
[解决办法]
mark!^_^
[解决办法]
恩。有道理。。。。
[解决办法]
学习
[解决办法]
xuexi~
[解决办法]
shi'a,bu cuo.
[解决办法]
LZ谦虚阿
[解决办法]
挺不错的!!
顶一下吧!!
[解决办法]
向各位学习了!
[解决办法]
向楼主学习。
[解决办法]
学习支持!~
[解决办法]
好帖...
[解决办法]
学习了!
[解决办法]

[解决办法]
超漂亮的asp个人主页全站源码

内容:
为了感谢广大网友一直以来对夜末工作室的支持,并且在寒假和春节即将来临之季“夜末工作室”将“夜末流离asp全站源码优化后完全免费下载使用。
夜末流离演示地址:http://www.y-mo.cn/vip
夜末流离下载地址:http://www.y-mo.cn/Download_view.asp?id=2077

[解决办法]
路过
------解决方案--------------------


学习~
[解决办法]
接分
[解决办法]
谢谢了
[解决办法]
我JAVA写的..

Java code
    int store[] = new int[10];    boolean eq;    //生成数组    IntegerSet() {        for (int i = 0; i < store.length; i++) {            for (int x = 20; x < 80; x++) {                if (1 != (int) (Math.random() * 2) && this.checks(x, i) == false) {                    store[i] = x;                }            }        }    }    //检测是否有重复项    boolean checks(int x, int i) {        boolean ch = false;        for (int j = 0; j < i; j++) {            if (store[j] == x) {                ch = true;            }        }        return ch;    }}
[解决办法]
顶下!
[解决办法]
o
[解决办法]
顶下!
[解决办法]
好 不错 学习学习
[解决办法]
不错,学习学习
[解决办法]
以前犯过一个比这个还麻烦的错误,现在基本就不出错了
[解决办法]
没犯过这样的错误,不过学习了~谢谢~~~~
[解决办法]
谢谢分享
[解决办法]
UP
[解决办法]
学习了!

读书人网 >C#

热点推荐