柚子Nan--回归原点

Everything can be as easy as you like or as complex as you need.
posts - 233, comments - 985, trackbacks - 17, articles - 29
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

关于随机数的一个奇怪问题

Posted on 2005-01-25 11:40 柚子Nan 阅读(2258) 评论(14)  编辑 收藏 网摘 所属分类: [技术.Net]

今天上午同事遇到一个问题,他要生成一个任意位数的随机数字和大写字母的组合,一个很简单的问题。同事的代码如下:

private string GetRandomString(int nDigit)

{

    //将数字和大写字母组成一个字符串

    string[] arySource={"0","1","2","3","4","5","6","7","8","9"

                       ,"A","B","C","D","E","F","G","H","I","J","K","L"

                   ,"M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"};

    string strResult = "";

    string strTemp = "";

    for (int i = 0; i < nDigit; i++)

    {

        strTemp = arySource[new Random().Next(36)];

        strResult += strTemp;

    }

 

    return strResult;

}


然后在另外一个按钮的事件里

private void Button1_Click(object sender, System.EventArgs e)

{

    TextBox1.Text = GetRandomString (4);

}

 

如果运行程序,总是得到4位相同的数字或者字母。

但是,如果在for循环内部设置了断点,然后F9单步跟踪,就产生了4位不同的数字或者字母。

就是这样一个结论

如果F5运行程序就得到4相同的串

如果单步调试F9 就得到随机的串

试试看?

Feedback

#1楼    回复  引用    

2005-01-25 11:46 by Lostinet [未注册用户]
在极短的时间内
new Random().Next(36)
会返回相同的值.

建议
Random r=new Random(Guid.NewGuid().GetHashCode());
for(...)
{
.... r.Next(36);
}

#2楼 [楼主]   回复  引用  查看    

2005-01-25 11:52 by 柚子Nan      
楼上说得果然牛!

后来,我找到了一个解决方法

是这个对象new Random() 出了问题

如果把上述代码修改为

privatestring GetRandomString(int nDigit)

{

    //将数字和大写字母组成一个字符串

    string[] arySource={"0","1","2","3","4","5","6","7","8","9"

                       ,"A","B","C","D","E","F","G","H","I","J","K","L"

                   ,"M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"};

    string strResult = "";

    string strTemp = "";

    Random aRandom = new Random();

   

    for (int i = 0; i < nDigit; i++)

    {

        strTemp = arySource[aRandom.Next(36)];

        strResult += strTemp;

    }

 

    return strResult;

}

 

那么无论是单步调试F9,还是整体运行F5,都将得到正确的随机字符串。

好奇怪的问题,谁能解释解释

#3楼 [楼主]   回复  引用  查看    

2005-01-25 11:53 by 柚子Nan      
谢谢Lostinet

后来在msdn找到了答案:
Random 类,伪随机数是以相同的概率从一组有限的数字中选取的。所选数字并不具有完全的随机性,因为它们是用一种确定的数学算法选择的,但是从实用的角度而言,其随机程度已足够了。

随机数的生成是从种子值开始。如果反复使用同一个种子,就会生成相同的数字系列。产生不同序列的一种方法是使种子值与时间相关,从而对于 Random 的每个新实例,都会产生不同的系列。
要提高性能,请创建一个 Random,以便随着时间的推移可以生成很多随机数,而不要重复新建 Random 来生成一个随机数。

#4楼    回复  引用    

2005-01-25 11:55 by Lostinet [未注册用户]
你这样做依然是有问题的.

连续的两次 GetRandomString 会返回同样的字符串.

#5楼    回复  引用    

2005-01-25 12:04 by 梁利锋 [未注册用户]
应该将
Random aRandom = new Random();
改为类的一个静态属性:
private static Random aRandom = new Random();

#6楼    回复  引用    

2005-01-25 12:21 by hmgyh [未注册用户]
private Random rnd=new Random();

private string GetRandomString(int nDigit)

{

//将数字和大写字母组成一个字符串

string[] arySource={"0","1","2","3","4","5","6","7","8","9"

,"A","B","C","D","E","F","G","H","I","J","K","L"

,"M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"};

string strResult = "";

string strTemp = "";

for (int i = 0; i < nDigit; i++)

{

strTemp = arySource[rnd.Next(36)];

strResult += strTemp;

}



return strResult;

}
private void button1_Click(object sender, System.EventArgs e)
{
textBox1.Text = GetRandomString (4);

}

#7楼    回复  引用  查看    

2005-01-25 12:46 by EnjoyJob      
看来这个 Next () 函数和时间有关系

#8楼    回复  引用  查看    

2005-01-25 13:28 by 维生素C.net      
以前用vb的时候不就是这样吗?道理和vb中的差不多,random()函数是与时间有关的。

#9楼    回复  引用    

2005-01-25 13:57 by 柚子Nan [未注册用户]
Lostinet 是的
TextBox1.Text = GetRandomString (4) + GetRandomString (4);

得到的结果是GetRandomString (4)的复制1倍

最终的解决方案就是Lostinet 所说的
1、Random r=new Random(Guid.NewGuid().GetHashCode());
2、梁利锋 所说的设置为static变量。static必然与时间相关累积了


#10楼    回复  引用    

2005-01-25 15:40 by 梁利锋 [未注册用户]
NewGuid() 也是和时间相关的,只不过增加了对于电脑其它部分的一些信息,如网卡号等。而且,NewGuid() 本身想必也是使用Random产生的。

static 是为了保证初始化只被执行一次,其实应该在整个应用程序中共享这个Random实例,才保证了即使在不同的类中,也不会因执行的时间太接近而出现重复。

public class Test
{
private static Random rand = new Random();
private string arySource = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

public void Run()
{
string s = GetRandomString(4) + ":" + GetRandomString(4);
Console.WriteLine("{0}", s);
}

private string GetRandomString(int nDigit)
{
string strResult = "";
for (int i=0; i<nDigit; i++)
{
strResult += arySource[rand.Next(36)];
}
return strResult;
}
}

#11楼    回复  引用    

2005-01-25 20:57 by lay [未注册用户]
在VB里使用随机也是这样,当时是怎么处理的忘了,呵呵

#12楼    回复  引用  查看    

2005-01-25 22:39 by caca(卡卡)      
看来和C的random是一样的道理.

#include<stdlib.h>
#include<stdio.h>
#include<time.h>
main()
{
int i=0;
randomize();
for(i;i<100;i++)
{
/* randomize(); */
printf("%d ",random(10);
}
}

#13楼 [楼主]   回复  引用    

2005-03-09 21:25 by sorry [未注册用户]
http://www.tenback.net/DotNet/CodingStandards.aspx

#14楼    回复  引用    

2005-07-21 09:54 by 3ku [未注册用户]
new Random(int)作为一个种子就可以了




标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
Google站内搜索

相关文章:

相关链接: