Re: [問題] 亂數問題

看板C_and_CPP作者 (-858993460)時間14年前 (2011/03/06 20:56), 編輯推噓5(5013)
留言18則, 8人參與, 最新討論串3/4 (看更多)
※ 引述《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

03/06 21:12, , 1F
還是不太瞭解第一個的意思
03/06 21:12, 1F

03/06 21:12, , 2F
看到畫圖就覺得好佛心…
03/06 21:12, 2F

03/06 21:32, , 3F
推一個阿 XDD
03/06 21:32, 3F

03/06 21:39, , 4F
rand() 本來就已經沒有很亂了, 爭這麼一點點其實沒啥意義
03/06 21:39, 4F

03/06 21:39, , 5F
真的有需要精確亂數的話換一個演算法比較實際...
03/06 21:39, 5F

03/06 21:50, , 6F
這只是其中一個原因<
03/06 21:50, 6F

03/06 21:54, , 7F
有興趣的話請去查一下 C FAQ
03/06 21:54, 7F

03/06 22:14, , 8F
我覺得解釋的很好 m起來
03/06 22:14, 8F

03/09 05:51, , 9F
重取 mod 有個問題: 不確定性. 可能要重取多次才能得到
03/09 05:51, 9F

03/09 05:53, , 10F
極端例就是 x = RAND_MAX/2+2 時(16385), 每次都有一半的
03/09 05:53, 10F

03/09 05:55, , 11F
的機率要重取一次, 執行時間的不確定性比較大. :-)
03/09 05:55, 11F

03/11 02:39, , 12F
其實第一個方法也是一樣的 因為這時 bucket 會是 1
03/11 02:39, 12F

03/11 02:39, , 13F
依然一次會有一半的機率重取
03/11 02:39, 13F

03/11 02:39, , 14F
不過反正抓到我們想要的數字的期望次數是 2 次稍弱 就沒差了
03/11 02:39, 14F

03/11 02:42, , 15F
嘛話說回來 以上的說明都是建立在 rand() 夠亂的情形
03/11 02:42, 15F

03/11 02:43, , 16F
而 rand() 原本的實作只不過是簡單的 LCG
03/11 02:43, 16F

03/11 02:43, , 17F
它就是只能提供這種程度的亂度而已
03/11 02:43, 17F

03/11 02:44, , 18F
像四五樓說的要更好的話就換個演算法吧
03/11 02:44, 18F
文章代碼(AID): #1DSuIH6B (C_and_CPP)
討論串 (同標題文章)
本文引述了以下文章的的內容:
完整討論串 (本文為第 3 之 4 篇):
文章代碼(AID): #1DSuIH6B (C_and_CPP)