梅森旋轉法僞隨機數在delphi下實現

梅森旋轉法(也有翻譯爲馬特賽特旋轉算法)產生的僞隨機數比線性同餘法要好。產生隨機數的速度快、週期長,可達到2^19937-1,且具有623維均勻分佈的性質,對於一般的應用來說,足夠大了,序列關聯比較小,能通過很多隨機性測試。現在很多編程語言都默認用梅森旋轉法來提供僞隨機數比如c++從11開始加入了梅森旋轉法,但delphi一直都是用的線性同於法,在xe10.3還是這樣的:

//Random integer, implemented as a deterministic linear congruential generator
// with 134775813 as a and 1 as c.

在一個日本網站上找到了現成的梅森旋轉法Pascal代碼,直接保存爲pas文件即可使用。

使用方法:
 

procedure TForm1.FormCreate(Sender: TObject);
begin

Randomize; //原隨機數初始化
InitMT(Random(9999999)); //用線性同餘法生成的隨機數來初始化梅森旋轉法
end;

procedure TForm1.Button1Click(Sender: TObject);
begin

 memo1.Lines.Add(IRanMT.ToString); //獲取一個梅森旋轉隨機數
end;

梅森旋轉法單元代碼

{ ******************************************************************
    Mersenne Twister Random Number Generator for pascal
  ******************************************************************}

unit uranmt;

interface

procedure InitMT(Seed : LongInt);
{ Initializes MT generator with a seed }

procedure InitMTbyArray(InitKey : array of LongInt; KeyLength : Word);
{ Initialize MT generator with an array InitKey[0..(KeyLength - 1)] }

function IRanMT : cardinal;
{ Generates a Random number }

implementation

const
  N          = 624;
  M          = 397;
  MATRIX_A   = $9908b0df;  { constant vector a }
  UPPER_MASK = $80000000;  { most significant w-r bits }
  LOWER_MASK = $7fffffff;  { least significant r bits }

  mag01 : array[0..1] of Cardinal{LongInt} = (0, MATRIX_A);

var
  mt  : array[0..(N-1)] of Cardinal{LongInt};  { the array for the state vector }
  mti : Word;                        { mti == N+1 means mt[N] is not initialized }

procedure InitMT(Seed : LongInt);
var
  i : Word;
begin
  mt[0] := Seed and $ffffffff;
  for i := 1 to N-1 do
    begin
      mt[i] := (1812433253 * (mt[i-1] Xor (mt[i-1] shr 30)) + i);
        { See Knuth TAOCP Vol2. 3rd Ed. P.106 For multiplier.
          In the previous versions, MSBs of the seed affect
          only MSBs of the array mt[].
          2002/01/09 modified by Makoto Matsumoto }
      mt[i] := mt[i] and $ffffffff;
        { For >32 Bit machines }
    end;
  mti := N;
end;

procedure InitMTbyArray(InitKey : array of LongInt; KeyLength : Word);
var
  i, j, k, k1 : Word;
begin
  InitMT(19650218);

  i := 1;
  j := 0;

  if N > KeyLength then k1 := N else k1 := KeyLength;

  for k := k1 downto 1 do
    begin
      mt[i] := (mt[i] Xor ((mt[i-1] Xor (mt[i-1] shr 30)) * 1664525)) + InitKey[j] + j; { non linear }
      mt[i] := mt[i] and $ffffffff; { for WORDSIZE > 32 machines }
      i := i + 1;
      j := j + 1;
      if i >= N then
        begin
          mt[0] := mt[N-1];
          i := 1;
        end;
      if j >= KeyLength then j := 0;
    end;

  for k := N-1 downto 1 do
    begin
      mt[i] := (mt[i] Xor ((mt[i-1] Xor (mt[i-1] shr 30)) * 1566083941)) - i; { non linear }
      mt[i] := mt[i] and $ffffffff; { for WORDSIZE > 32 machines }
      i := i + 1;
      if i >= N then
        begin
          mt[0] := mt[N-1];
          i := 1;
        end;
    end;

    mt[0] := $80000000; { MSB is 1; assuring non-zero initial array }
end;

function IRanMT : cardinal;
var
  y : cardinal;
  k : Word;
begin
  if mti >= N then  { generate N words at one Time }
    begin
      { If IRanMT() has not been called, a default initial seed is used }
      if mti = N + 1 then InitMT(5489);

      for k := 0 to (N-M)-1 do
        begin
          y := (mt[k] and UPPER_MASK) or (mt[k+1] and LOWER_MASK);
          mt[k] := mt[k+M] xor (y shr 1) xor mag01[y and $1];
        end;

      for k := (N-M) to (N-2) do
        begin
          y := (mt[k] and UPPER_MASK) or (mt[k+1] and LOWER_MASK);
          mt[k] := mt[k - (N - M)] xor (y shr 1) xor mag01[y and $1];
        end;

      y := (mt[N-1] and UPPER_MASK) or (mt[0] and LOWER_MASK);
      mt[N-1] := mt[M-1] xor (y shr 1) xor mag01[y and $1];

      mti := 0;
    end;

  y := mt[mti];
  mti := mti + 1;

  { Tempering }
  y := y xor (y shr 11);
  y := y xor ((y shl  7) and $9d2c5680);
  y := y xor ((y shl 15) and $efc60000);
  y := y xor (y shr 18);

  IRanMT := y
end;

const
  init : array[0..3] of LongInt = ($123, $234, $345, $456);

begin
  InitMTbyArray(init, 4);
end.

{ ******************************************************************
    Mersenne Twister Random Number Generator end
  ******************************************************************}

更多代碼可以在這日本網站看到:http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/PASCAL/pascal.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章