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個隨機數,運行結果如下:  

  

 

 

   需要注意的是,雖然看上去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();
}

  運行結果:

  

 

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個隨機數,運行結果如下:

  

 

   從結果可以看出來,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();
        }
    }
}

  執行結果:

  

 

   可見a對象和b對象是使用相同的種子123構造出來的,之后它們每次生成的隨機數的值都是一樣的。而如果使用默認的構造方法(以時間為種子)則不會有這種情況。

   注:之所以調用Thread.Sleep(1000);是為了錯開兩次構造隨機數對象的時間,如果不這么做的話,使用默認構造方法,連續兩次調用Random()得到的結果仍然可能會一樣,因為兩次調用Random()時的時間是一樣的。

  我還沒有去研究過windows系統時間的最小單位,按一般經驗判斷可能是us,想想1us內調用兩次構造方法時間是夠夠的吧。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM