顯示廣告
隱藏 ✕
看板 TL
作者 TL (踢欸樓)
標題 [筆記] 亂數問題
時間 2013年01月27日 Sun. PM 05:50:26


看板 C_and_CPP
作者 LPH66 (-858993460)
標題 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
tjjh89017:還是不太瞭解第一個的意思1F 03/06 21:12
cobrasgo:看到畫圖就覺得好佛心…2F 03/06 21:12
loveme00835:推一個阿 XDD3F 03/06 21:32
uranusjr:rand() 本來就已經沒有很亂了, 爭這麼一點點其實沒啥意義4F 03/06 21:39
uranusjr:真的有需要精確亂數的話換一個演算法比較實際...
ykjiang:這只是其中一個原因<6F 03/06 21:50
ykjiang:有興趣的話請去查一下 C FAQ
nowar100:我覺得解釋的很好 m起來8F 03/06 22:14
iamlouis:重取 mod 有個問題: 不確定性. 可能要重取多次才能得到9F 03/09 05:51
iamlouis:極端例就是 x = RAND_MAX/2+2 時(16385), 每次都有一半的
iamlouis:的機率要重取一次, 執行時間的不確定性比較大. :-)
LPH66:其實第一個方法也是一樣的  因為這時 bucket 會是 112F 03/11 02:39
LPH66:依然一次會有一半的機率重取
LPH66:不過反正抓到我們想要的數字的期望次數是 2 次稍弱 就沒差了
LPH66:嘛話說回來  以上的說明都是建立在 rand() 夠亂的情形
LPH66:而 rand() 原本的實作只不過是簡單的 LCG
LPH66:它就是只能提供這種程度的亂度而已
LPH66:像四五樓說的要更好的話就換個演算法吧

--
Shaken, Not Stirred.
--
※ 作者: TL 時間: 2013-01-27 17:50:26
※ 看板: TL 文章推薦值: 0 目前人氣: 0 累積人氣: 33 
分享網址: 複製 已複製
guest
x)推文 r)回覆 e)編輯 d)刪除 M)收藏 ^x)轉錄 同主題: =)首篇 [)上篇 ])下篇