返回列表 上一主題 發帖

自己寫 自己的方式產生亂數

回復 8# sjgau
自己寫真的可以發現很多問題,學到很多,
希望能拋磚引玉,我是採用Microsoft Visual Basic 的那組參數,仿造rnd函數一樣傳回single。
  1. Function myRnd(Optional Number) As Single
  2.   Dim tmp As Double
  3.   'LCG Algorithm:
  4.   '  X(n+1) = (a * X(n) + c) mod m
  5.   Const a As Long = 1140671485
  6.   Const c As Long = 12820163
  7.   Const m As Long = 16777216  '2^24
  8.   Const x0 As Long = 1     '根據你使用哪組參數,x0有時有需要符合的條件。
  9.   
  10.   Static seed As Variant
  11.   '利用IsEmpty判斷,來初始化一 static變數為非零值。
  12.   If IsEmpty(seed) Then seed = x0
  13.   
  14.   '利用IsMissing判斷 optional 參數是否傳入,若函數有傳入參數時,設為種子。
  15.   If Not IsMissing(Number) Then seed = Number
  16.    
  17.   'myRnd = (a * seed + c) Mod m
  18.   '(a * seed + c)過大時,mod 會發生溢位,只能用其他方法求。
  19.   
  20.   tmp = a * seed + c  'double
  21.   seed = tmp - m * Fix(tmp / m)   '即計算 (a * seed + c) Mod m,此為產生的亂數值,並設為下次種子
  22.   myRnd = seed / m  '使傳回亂數值介於0到1之間
  23. End Function
複製代碼

TOP

本帖最後由 stillfish00 於 2013-11-1 08:20 編輯

回復 13# stillfish00
實測後仍不滿意,呼叫m次後,不會回到第一組產生的隨機數,
主因是 tmp = a * seed + c 即便是 double 數仍存有精確度誤差...   

LongLong又只有在64位元平台上可以使用

TOP

回復 15# c_c_lai
其實我的意思是這樣:
  1. Sub EX()
  2.   Dim a As Single, b As Single
  3.   Dim i
  4.   
  5.   a = Rnd
  6.   For i = 2 To 16777216
  7.     Rnd
  8.   Next
  9.   b = Rnd
  10.   Debug.Print a, b
  11.   
  12.   a = myRnd
  13.   For i = 2 To 16777216
  14.     myRnd
  15.   Next
  16.   b = myRnd
  17.   Debug.Print a, b
  18.   
  19. End Sub
複製代碼
像rnd一樣,這m次取的亂數都會不一樣,
但rnd取完m次後,再取下一次時,會回到第一次取的值,再一次循環。
就像LCG裡面提到的生命週期

TOP

回復  stillfish00
實測後仍不滿意,呼叫m次後,不會回到第一組產生的隨機數,
主因是 tmp = a * seed +c  ...
stillfish00 發表於 2013-11-1 08:16


後來改為 tmp = (a mod m) *( seed mod m) + c 即可,
產生之模數不變,又因m = 2^24時, tmp為小於2^49之整數,
double之精確度可完整表示,不會有誤差。
#16 測試也可正常循環。

TOP

        靜思自在 : 【是否發揮了良能?】人間壽命因為短暫,才更顯得珍貴。難得來一趟人間,應問是否為人間發揮了自己的良能,而不要一味求長壽。
返回列表 上一主題