• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
yoxking
yoxking Tech.
博客园    首页    新随笔    联系   管理    订阅  订阅

随机数

对于随机数,大家都知道,计算机不可能产生完全随机的数字,所谓的随机数发生器都是通过一定的算法对事先选定的随机种子做复杂的运算,用产生的结果来近似的模拟完全随机数,这种随机数被称作伪随机数。伪随机数是以相同的概率从一组有限的数字中选取的。所选数字并不具有完全的随机性,但是从实用的角度而言,其随机程度已足够了。伪随机数的选择是从随机种子开始的,所以为了保证每次得到的伪随机数都足够地“随机”,随机种子的选择就显得非常重要。如果随机种子一样,那么同一个随机数发生器产生的随机数也会一样。一般地,我们使用同系统时间有关的参数作为随机种子,这也是.net   Framework中的随机数发生器默认采用的方法。  


我们可以使用两种方式初始化一个随机数发生器:  

第一种方法不指定随机种子,系统自动选取当前时间作为随机种子:  

Random   ro   =   new   Random();  


第二种方法可以指定一个int型参数作为随机种子:  


int   iSeed=10;  

Random   ro   =   new   Random(10);  

之后,我们就可以使用这个Random类的对象来产生随机数,这时候要用到Random.Next()方法。这个方法使用相当灵活,你甚至可以指定产生的随机数的上下限。  

不指定上下限的使用如下:  

int   iResult;  

iResult=ro.Next();  


下面的代码指定返回小于100的随机数:

int   iResult;

int   iUp=100;  

iResult=ro.Next(iUp);  

而下面这段代码则指定返回值必须在50-100的范围之内:  


int   iResult;  

int   iUp=100;  

int   iDown=50;  

iResult=ro.Next(iDown,iUp);  


除了Random.Next()方法之外,Random类还提供了Random.NextDouble()方法产生一个范围在0.0-1.0之间的随机的双精度浮点数:  


double   dResult;  

dResult=ro.NextDouble();  


另外一个与Random.NextDouble()方法相似的方法是Random.Sample(),它跟Random.NextDouble()方法唯一的区别在于访问级别,我们可以看看它们的原始声明:  


protected   virtual   double   Sample();  

public   virtual   double   NextDouble();  


Random.Sample()方法是保护方法,只允许子类的对象访问,而Random.Sample()方法则可以看作是Random.Sample()的公开版本。一般地,用户在Random的子类中重写Sample()方法来得到更一般的分布。  

这个例子中,我们使用Random.Next()方法来产生随机数。  

下面这个函数是这个例子的核心,我们利用他来产生一个随机的int数组:  

private   int   []GetRandomArray(int   Length,int   Up,int   Down){   int   iFirst=0;   int   []rtArray=new   Int32[Length];   Random   ro=new   Random(Length*unchecked((int)DateTime.Now.Ticks));   iFirst=ro.Next(Up,Down);   rtArray[0]=iFirst;   for(int   i=1;i  

读者或许都注意到了,我们采用了一种相当麻烦的方式来产生这个随机数组,为什么不简单地使用如下代码呢?请先看下面代码,这里我们使用了系统时间作为随机种子,连续获取两个随机数,并且将其输出:

<   %@   Page   Language= "C# "   Debug= "true "   Trace= "false "   TraceMode= "SortByCategory "%   > <   %   @Import   namespace= "System "   %   >
<   script   language=C#   runat=server   >
public   void   Page_Load(object   sender,EventArgs   e){   int   re=0;   int   re1=0;   GetRandomDefault(ref   re);   GetRandomDefault(ref   re1);   RandomNum.Text=re.ToString();   RandomNum.Text+= "   "+re1.ToString();}private   void   GetRandomDefault(ref   int   re){   Random   ro=new   Random(unchecked((int)DateTime.Now.Ticks));   re=ro.Next(10,20);}private   void   GetRandomByInt(ref   byte   []re){   Random   ro=new   Random();   ro.NextBytes(re);}
<   /script   >
<   html   >
<   head   >
<   title   > 随机数测试 <   /title   >
<   meta   http-equiv= "Content-Type "   content= "text/html;   charset=gb2312 "   >
<   /head   >

<   body   bgcolor= "#FFFFFF "   text= "#000000 "   >
<   form   runat=server   >
<   asp:Label   id= "RandomNum "   runat=server   /   >

<   /form   >
<   /body   >
<   /html   >


是的,如你所见,产生了一样的两个随机数,无论重复多少次,都是一样的。原因在哪里呢?  


不要以为使用系统时间作为随机种子就万无一失了——如果应用程序在一个较快的计算机上运行,则该计算机的系统时钟可能没有时间在此构造函数的调用之间进行更改,Random   的不同实例的种子值可能相同。这种情况下,我们就需要另外的算法来保证产生的数字的随机性。所以为了保证产生的随机数足够“随机”,我们不得不使用复杂一点的方法来获得随机种子。  

在上面的这段程序中,我们首先使用系统时间作为随机种子,然后将上一次产生的随机数跟循环变量和一个与系统时间有关的整型参数相乘,以之作为随机种子,从而得到了每次都不同的随机种子,保证了产生足够“随机”的随机数。  


得到整型的随机数组以后,我们将它变成字符串,然后使用System.Drawing中与GDI+相关的类生成一个图片并且在网页上显示出来。

  生成图片的ASP.net页面全部代码如下:

<   %@   Page   Language= "C# "   Debug= "true "   Trace= "false "   TraceMode= "SortByCategory "%   > <   %   @Import   namespace= "System.Drawing "   %   > <   %   @Import   namespace= "System.Drawing.Imaging "   %   > <   %   @Import   namespace= "System.Drawing.Text "   %   > <   %   @Import   namespace= "System.IO "   %   > <   script   language=C#   runat=server   >
public   void   Page_Load(object   sender,EventArgs   e){   string   strNum=GetRandomString();
string   strFontName;
int   iFontSize;
int   iWidth;
int   iHeight;  
strFontName= "宋体 ";
iFontSize=12;
iWidth=10*strNum.Length;
iHeight=25;

Color   bgColor=Color.Yellow;
Color   foreColor=Color.Red;

Font   foreFont=new   Font(strFontName,iFontSize,FontStyle.Bold);

Bitmap   Pic=new   Bitmap(iWidth,iHeight,PixelFormat.Format32bppArgb);
Graphics   g=Graphics.FromImage(Pic);
Rectangle   r=new   Rectangle(0,0,iWidth,iHeight);

g.FillRectangle(new   SolidBrush(bgColor),r);

g.DrawString(strNum,foreFont,new   SolidBrush(foreColor),2,2);
MemoryStream   mStream=new   MemoryStream();
Pic.Save(mStream,ImageFormat.Gif);
g.Dispose();
Pic.Dispose();

Response.ClearContent();
Response.ContentType= "image/GIF ";
Response.BinaryWrite(mStream.ToArray());
Response.End();
}
private   int   []GetRandomArray(int   Length,int   Up,int   Down)
{
int   iFirst=0;
int   []rtArray=new   Int32[Length];
Random   ro=new   Random(Length*unchecked((int)DateTime.Now.Ticks));
iFirst=ro.Next(Up,Down);
rtArray[0]=iFirst;
for(int   i=1;i <   Length;i++)
{
Random   ri=new   Random(i*iFirst*unchecked((int)DateTime.Now.Ticks));
rtArray[i]=ri.Next(Up,Down);
iFirst=rtArray[i];
}
return   rtArray;
}


其中生成图片的部分相对复杂,但由于不是本文的主题所在,所以本文不对之做详细说明,有兴趣的读者可以参考杜亮编写的《亲密接触ASP.net》一书中的相关内容。

最后我们可以编写一个普通的HTML页面来查看效果,只要把图片的src属性指向这个页面就行了(这里我们假设上面那个ASP.net文件的名字是“RandomPic.aspx”):

<   !DOCTYPE   HTML   PUBLIC   "-//W3C//DTD   HTML   4.0   Transitional//EN "   >
<   HTML   >
<   HEAD   >
<   TITLE   >   New   Document   <   /TITLE   >
<   META   NAME= "Generator "   CONTENT= "EditPlus "   >
<   META   NAME= "Author "   CONTENT= " "   >
<   META   NAME= "Keywords "   CONTENT= " "   >
<   META   NAME= "Description "   CONTENT= " "   >
<   /HEAD   >

<   BODY   >
<   img   src= "RandomPic.aspx "   >
<   /BODY   >

<   /HTML   >





要实现像Chinaren网站那样的防恶意攻击的效果,只需要在留言簿的页面里产生随机数并且编写相应的JavaScript验证代码(事实上这个工作可以交给ASP.net的验证控件很容易地完成),然后传递到生成图片的页面里生成图片提示用户就可以了。  

除此以外,随机数还有其它很多用途,特别是开发游戏的时候更是必不可少。到此,读者应该完全掌握在ASP.net中随机数的产生方法,如此,本文的目的也就达到了。  

最后,有兴趣的读者可以试着解决这个问题:  

在桥牌游戏中,发牌可以视作一个随机过程,但是后续过程受到前面的影响,即已经发出去的牌不可能再次发出。试编写一个程序模拟发牌过程。  

 

如下生成0到100的随机数:
Random   r   =   new   Random(DateTime.Now.Millisecond);
int   i   =   r.Next(100);

//-----------------------取随机产生的认证码(N位数字)
        public   string   GetByRndNum()
        {
                string   Vchar   =   "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,w,x,y,z "   ;
                string[]   VcArray   =   Vchar.Split( ', ');
                string   VNum   =   " ";                
                //采用一个简单的算法以保证生成随机数的不同
                Random   rand   =   new   Random();
                int[]   rndArr   =   new   int[rndLength];
                for   (int   i   =   1;   i   <   rndLength   +   1;   i++)
                {      
                        if(i> 1)
                        {
                                do
                                {
                                        rndArr[i-1]   =   rand.Next(10);//rand.Next(35)   ;
                                        bool   goon   =   false;
                                        for(int   ix=0;   ix <i-1;   ix++)
                                        {
                                                if   (rndArr[ix]   ==   rndArr[i-1])
                                                {
                                                        goon   =   true;
                                                        break;
                                                }
                                        }
                                        if   (!goon)
                                                break;
                                }   while   (1   ==   1);
                        }
                        else
                                rndArr[i-1]   =   rand.Next(10);
                        VNum   +=   rndArr[i-1];
                }
                return   VNum;
        }
}

posted @ 2008-03-24 19:36  yoxking   阅读(350)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3