[C#]亂數亂不亂

大家在使用亂數上,大多是採用 Random 這個類別,套用 MSDN 的說明:

虛擬亂數是以相等的機率從有限的數字集中選取。選取的數字並非是完全隨機,因為是使用有限性數學演算法來選取它們,但是用於實際用途已足夠。目前 Random 類別的實作是以 Donald E. Knuth 的減法亂數產生器演算法為基準。

事實上亂數主要是依賴所謂的種子(或許現今的程式太方便,定義時基本上不需要你輸入種子數,但在以前,亂數使用要建構種子,如下)

Randomize Timer
Dim R As Integer
R = Int(Rnd * 100) + 1

在VB6以前亂數大概都是透過這樣來撰寫(或許有些人會省略 Timer,因為沒定義的話通常也是透過時間來取得種子數)
那其實演算法是透過數學的方式來產生一個亂數的,其實他的雜亂度並不夠,所以在 .Net 中另外提供了 RNGCryptoServiceProvider 這個類別,可以提供你更加雜亂的亂數

using System;
using System.Security.Cryptography;

/// <summary>
/// 使用 RNGCryptoServiceProvider 產生由密碼編譯服務供應者 (CSP) 提供的亂數產生器。
/// </summary>
public static class RNG
{
    private static RNGCryptoServiceProvider rngp = new RNGCryptoServiceProvider();
    private static byte[] rb = new byte[4];

    /// <summary>
    /// 產生一個非負數的亂數
    /// </summary>
    public static int Next()
    {
        rngp.GetBytes(rb);
        int value = BitConverter.ToInt32(rb, 0);
        if (value < 0) value = -value;
        return value;
    }
    /// <summary>
    /// 產生一個非負數且最大值 max 以下的亂數
    /// </summary>
    /// <param name="max">最大值</param>
    public static int Next(int max)
    {
        rngp.GetBytes(rb);
        int value = BitConverter.ToInt32(rb, 0);
        value = value % (max + 1);
        if (value < 0) value = -value;
        return value;
    }
    /// <summary>
    /// 產生一個非負數且最小值在 min 以上最大值在 max 以下的亂數
    /// </summary>
    /// <param name="min">最小值</param>
    /// <param name="max">最大值</param>
    public static int Next(int min, int max)
    {
        int value = Next(max - min) + min;
        return value;
    }
}

上述是保哥那將之實作成靜態類別的程式碼,相信透過他可以快速取得一個夠亂的亂數
----
作了幾次實驗,發現透過 RNGCryptoServiceProvider 來產生亂數的話,值是夠亂
可是因為他是透過將亂數一個一個往 byte 裡面塞,所以問題也就來了,因為不可能連續取出多個 byte 全為 0 的,所以遇到的結果會是如果單純透過他的 Next 取值,你大概取不到太小的數了(第一個 byte 不全為 0 你就別想取得不包含第一 byte 的數了),所以真正有用的大概是透過 mod 來取一個介於之間的數,因為是從大範圍中砍一小段下來,以10為例,就算產生的是 16,777,215 ~ 2,147,483,647 中間夠亂的整數(取 16,777,215 的原因是因為我假設第 1 byte 就好死真的全 0,機率其實應該是非常的低),那我 mod 10 這種與最小數落差還蠻大的數,其實還是可能出現非常凌亂的結果的

2011/11/20 補充

 


本文同步發表於 Blogger

Reference:
MSDN:Random類別
MSDN:RNGCryptoServiceProvider類別
亂數產生器:Random 與 RNGCryptoServiceProvider

留言

這個網誌中的熱門文章

DB 資料庫呈現復原中

Outlook 刪除大量重覆信件

[VB.Net] If vs IIf ,兩者的差異