C#随机数

  随机数的类为Random,命名空间为System。

  转到Random的定义可以看到如下代码(我把注释删掉了):

namespace System
{
    public class Random
    {
        public Random();
        public Random(int Seed);
public virtual int Next(); public virtual int Next(int minValue, int maxValue); public virtual int Next(int maxValue); public virtual void NextBytes(byte[] buffer); public virtual double NextDouble(); protected virtual double Sample(); } }

  我们从易到难挨个说说。

Random();

  这是无参构造方法,比如在程序中这样写:

Random a = new Random();

  得到的a就是一个随机数生成器,它可以用来生成随机数。

int Next();

  这个方法返回值为int类型,调用它就能得到一个随机数,反复调用就能反复得到随机数。

  例:

        static void Main(string[] args)
        {
            Random a = new Random();
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine(a.Next());
            }

            Console.ReadKey();
        }

  这样就得到了10个随机数,运行结果如下:  

  C#随机数

 

 

   需要注意的是,虽然看上去Next方法返回值是int类型,但实际上它只返回非负整数,而且不包括int类型能表示的最大的那个整数(2^31 - 1)

int Next(int minValue, int maxValue);

  这个方法能指定随机数的生成范围,左闭右开区间,即生成的数能包含minValue,不包含maxValue。可以包含负数。但是maxValue的值不能大于minValue的值,否则运行时会抛出异常。

int Next(int maxValue);

  这个方法指定随机数的最大值(不包含maxValue),并且它也只能生成非负整数,与Next(0, maxValue)是一个道理,如果传入的maxValue为负数,那么运行时抛出异常,如果maxValue的值为0或1,那么生成的随机数只能是0。

double NextDouble();

  这个方法能返回一个大于或等于 0.0 且小于 1.0 的随机浮点数。

void NextBytes(byte[] buffer);

  这个方法传入指定长度的byte类型的数组,用byte类型的随机数填充数组,如:

static void Main(string[] args)
{
    Random a = new Random();
    byte[] b = new byte[10];

    a.NextBytes(b);
    foreach(byte i in b)
    {
        Console.WriteLine(i);
    }

    Console.ReadKey();
}

  运行结果:

  C#随机数

 

double Sample();

  这个方法比较特殊,从声明可以看出来,其他的方法权限都是public,这个方法是protected。从方法的描述上能看到,这个方法返回的也是大于或等于 0.0 且小于 1.0 的随机浮点数,它与NextDouble看上去似乎只是权限不一样,看了下面这段代码就知道了:

namespace sdq
{
    class MyRandom : Random
    {
        protected override double Sample()
        {
            return 0.125;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            MyRandom a = new MyRandom();

            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine(a.NextDouble());
            }
            Console.ReadKey();
        }
    }
}

  代码分析:

  首先定义了一个类MyRandom,继承至Random,由于Random中的Sample()是虚方法,因此可以在派生类中将Sample()重写,我在这里是将它固定返回0.125。在Main方法中构造了a这个对象,并且调用了a.NextDouble()去生成10个随机数,运行结果如下:

  C#随机数

 

   从结果可以看出来,Random的Sample方法可以改变NextDouble()方法的行为,如果用户想自定义获取随机数的方法,则可以通过重写Sample来实现。

Random(int Seed);

  最后再说一下这个带参构造函数,它用来在构造对象时指定随机数生成器的种子,而不带参的构造函数则是以时间作为种子。至于种子是个什么东西,我也不知道,通过下面这个例子也许能说明:

using System;
using System.Threading;

namespace test
{
    class Program
    {
        static void Main(string[] args)
        {
            Random a = new Random(123);
            Thread.Sleep(1000);
            Random b = new Random(123);

            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine("{0}\t{1}", a.Next(), b.Next());
            }
            Console.ReadKey();
        }
    }
}

  执行结果:

  C#随机数

 

   可见a对象和b对象是使用相同的种子123构造出来的,之后它们每次生成的随机数的值都是一样的。而如果使用默认的构造方法(以时间为种子)则不会有这种情况。

   注:之所以调用Thread.Sleep(1000);是为了错开两次构造随机数对象的时间,如果不这么做的话,使用默认构造方法,连续两次调用Random()得到的结果仍然可能会一样,因为两次调用Random()时的时间是一样的。

  我还没有去研究过windows系统时间的最小单位,按一般经验判断可能是us,想想1us内调用两次构造方法时间是够够的吧。

上一篇:C# 上传文件过大引起的报错


下一篇:SpringMVC响应