看板 TL
作者 標題 [筆記] 亂數問題
時間 2013年01月27日 Sun. PM 05:50:26
看板 C_and_CPP
作者 標題 Re: [問題] 亂數問題
時間 Sun Mar 6 20:56:47 2011
※ 引述《gauss760220 (章魚)》之銘言:
: 各位好
: 我剛學C++
: 目前學到有關亂數rand()的寫法
: 看了幾次還是不太懂
: 所以想po上來跟大家討論
: rand()是否為0~32767的數值?(這部分我不知有無理解錯誤)
: 以下為想問的程式
: randomize an integer in [0,100) :
: const int bucket = RAND_MAX / 100;
: do {r=rand()/bucket;} while (r>= 100);
: 就我的想法是
: RAND_MAX為32767 除以100後 bucket=327(因為整數除法)
: 接下來的do~while loop就看不太懂他在做什麼動作了
: 請高手指點
: 謝謝
這原理其實還是一樣簡單
假設我們想要一個 [0,x) 之間的隨機亂整數好了
那麼它的做法就是把 0 到 RAND_MAX 之間切成一樣長的 x 段 每段代表一個值
0 bucket 2*bucket 3*bucket (x-1)*bucket RAND_MAX = x*bucket
┌────┬────┬────┬ ┬────┐
│ │ │ │ ………… │ │
└────┴────┴────┴ ┴────┘
0 1 2 x-1
大概像這種感覺
要達成這樣的最簡單的解法就是把 rand() 值除以 bucket (就是每段的長度)
這樣這個分布就會自然讓各個數字平均出現 (因為每段一樣長)
不過這個圖只有在 RAND_MAX 能被 x 整除時才會像上面這樣
如果不能整除的時候會變成這樣:
0 bucket 2*bucket 3*bucket (x-1)*bucket x*bucket RAND_MAX
┌────┬────┬────┬ ┬────┬──┐
│ │ │ │ ………… │ │ │
└────┴────┴────┴ ┴────┴──┘
0 1 2 x-1 x
右邊有一小段 rand() 的結果直接除以 bucket 後會得到 x
所以就需要這個 while 迴圈來把這段的結果給濾掉
以原 PO 的例子來看 RAND_MAX = 32767 x = 100
那右邊那一段就相當於 rand() 得到 32700~32767 這個範圍
那個 while 迴圈只不過就是把這段給濾掉而已
---
至於另一種常用的 mod 做法只不過是把分布弄成這個樣子而已:
0 RAND_MAX
┌─────────────── ─────┐
│ ………… │
└─────────────── ─────┘
0123...(x-1)0123...(x-1)0123...(x-1).........
那在 RAND_MAX 能被 x 整除時 最右邊會停在 x-1
這樣每個數字的機率就都是一樣的
但如果 RAND_MAX 不能被 x 整除時 最右邊會停在 (RAND_MAX % x) - 1
這就會造成 0 到這個數的出現機率比其他數多了那麼一點點
(這應該就是有些地方在說不要用 mod 取亂整數的原因...)
改法同樣簡單 把最右邊那一段不到 x 的切掉就好
(也就是當 rand() 出現比 RAND_MAX - (RAND_MAX % x) 大的數字時就重取)
計算上也不會複雜到哪裡去就是了...
(所以我實在搞不懂那些只會叫說別用 mod 取亂數而不提怎麼改進的文章在想什麼)
--
"LPH" is for "Let Program Heal us"....
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 140.112.28.92
推 :還是不太瞭解第一個的意思1F 03/06 21:12
推 :看到畫圖就覺得好佛心…2F 03/06 21:12
推 :推一個阿 XDD3F 03/06 21:32
→ :rand() 本來就已經沒有很亂了, 爭這麼一點點其實沒啥意義4F 03/06 21:39
→ :真的有需要精確亂數的話換一個演算法比較實際...
→ :真的有需要精確亂數的話換一個演算法比較實際...
→ :這只是其中一個原因<6F 03/06 21:50
→ :有興趣的話請去查一下 C FAQ
→ :有興趣的話請去查一下 C FAQ
推 :我覺得解釋的很好 m起來8F 03/06 22:14
推 :重取 mod 有個問題: 不確定性. 可能要重取多次才能得到9F 03/09 05:51
→ :極端例就是 x = RAND_MAX/2+2 時(16385), 每次都有一半的
→ :的機率要重取一次, 執行時間的不確定性比較大. :-)
→ :極端例就是 x = RAND_MAX/2+2 時(16385), 每次都有一半的
→ :的機率要重取一次, 執行時間的不確定性比較大. :-)
→ :其實第一個方法也是一樣的 因為這時 bucket 會是 112F 03/11 02:39
→ :依然一次會有一半的機率重取
→ :不過反正抓到我們想要的數字的期望次數是 2 次稍弱 就沒差了
→ :嘛話說回來 以上的說明都是建立在 rand() 夠亂的情形
→ :而 rand() 原本的實作只不過是簡單的 LCG
→ :它就是只能提供這種程度的亂度而已
→ :像四五樓說的要更好的話就換個演算法吧
→ :依然一次會有一半的機率重取
→ :不過反正抓到我們想要的數字的期望次數是 2 次稍弱 就沒差了
→ :嘛話說回來 以上的說明都是建立在 rand() 夠亂的情形
→ :而 rand() 原本的實作只不過是簡單的 LCG
→ :它就是只能提供這種程度的亂度而已
→ :像四五樓說的要更好的話就換個演算法吧
--
Shaken, Not Stirred.
--
※ 作者: TL 時間: 2013-01-27 17:50:26
※ 看板: TL 文章推薦值: 0 目前人氣: 0 累積人氣: 33
回列表(←)
分享