主講人: jserv / 課程討論區: 2023 年系統軟體課程
返回「Linux 核心設計/實作」課程進度表Image Not Showing Possible ReasonsLearn More →
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
shuffle
利用 Fisher–Yates shuffle 演算法來實作洗牌(shuffle)
q_size
取得 queue 的大小 len
。random
,然後 old
將指向從前面數來第 random 個節點,new
會指向最後一個未被抽到的節點,將 old
和 new
指向的節點的值交換,再將 len - 1。shuffle
Pearson's chi-squared test 能檢驗虛無假說(Null hypothesis),即某特定事件在樣本中觀察到的頻率分佈與特定理論分佈一致,事件必須是互斥且機率為 1。
如果要 shuffle 三個不同的數字,會出現六種可能的結果,彼此是互斥的,且發生機率加起來為 1。那假設 shuffle 是公平的(六種結果發生的機率相同),並遵守 Uniform distribution,那虛無假說為:
接下來透過 Pearson's chi-squared test 來驗證 shuffle 三個數字的頻率是符合 Uniform distribution:
在測試 shuffle 1000000 次後,六種結果各自的頻率如下表:
觀察到的頻率 | 期待的頻率 | ||
---|---|---|---|
[1, 2, 3] | 166391 | 166666 | 0.45375181500726003 |
[2, 1, 3] | 166829 | 166666 | 0.15941463765855063 |
[2, 3, 1] | 166807 | 166666 | 0.11928647714590858 |
[1, 3, 2] | 166790 | 166666 | 0.0922563690254761 |
[3, 1, 2] | 166862 | 166666 | 0.23049692198768795 |
[3, 2, 1] | 166321 | 166666 | 0.7141528566114265 |
Total | 1.76935907743631 |
= 1.76935907743631
對於 N 個隨機樣本而言,自由度為 N - 1。我們 shuffle 3 個數字會有六種結果,因為加起來機率為 1 ,所以實際上可以自由變換的變數只有五個,其中一個結果的機率為 1 減去另外五個結果發生的機率,所以自由度為 5。
對於要拒絕的虛無假說(),觀察到的結果必須具有統計顯著性,即觀察到的 P value 小於預先指定的顯著水準 α。
因為 P value(0.8~0.9)> alpha(0.05),統計檢定的結果不拒絕虛無假說()
也就是樣本資料不拒絕 shuffle 的結果遵循 Uniform distribution,因為沒有足夠證據推翻。
從圖表來看 shuffle 的頻率是大致符合 Uniform distribution 的。
scripts/driver.py
用到 subprocess.call()
來產生新行程以執行指定的命令,然後等待命令完成後取得 return code,後續再檢查 return code 是否為 0 來得知測試是否成功。
因為這裡的測試我想取得 stdout,所以改用 subprocess.run()
,會執行參數中指定的命令,然後等待命令完成後,會回傳一個 CompletedProcess instance。
取得 CompletedProcess.stdout
再做編碼後,可以得到 stdout 的字串。
後續再將得到的輸出字串取出 shuffle 過後的結果,放到 nums
變數中。
測試 [1, 2, 3, 4] 做 shuffle 1,000,000 次的直方圖:
討論 Random Number Generator 夠不夠亂之前,要先回答以下二個問題:
亂數直覺而言是個很簡單的概念,一般來說,我們認爲一個事件「亂」,表示我們無法預測該事件的結果,但統計學卻讓所謂的「亂」有跡可循,透過機率分佈的概念,我們即便無法準確的預測下一次的事件結果爲何,卻可以很「確定」的表示隨機事件的結果落在某個範圍內的機率是多少,或長期而言結果的統計量會趨近於某個確定的值 – 我們可以用機率分佈來「描述」隨機事件。
另一個角度來看,我們可能認爲一段文字是隨機的,如果我們無法從該段文字中讀出資訊,例如 "woif ejxv nwe" 可能是一個隨機的字串而 "what the f*ck" 則不是隨機 – 資訊的含量也可以用來描述隨機性。
從上面的兩個觀點中,我們可以截取出兩個概念,並討論看看這他們與亂數的關係 – probability & information
一個事件的結果無跡可循,換句話說結果發生在任何位置的機率是均等的,這樣的性質可以用 uniform distribution 來表達,但光是 uniform 是不夠的,考慮一個數列: 可以預期結果會是分佈在 的正整數,且發生的頻率均等,但我們不會認爲這樣的數列是隨機的,因爲我們可以很容易的發現事件之間有前後關係,所以還要再多加上一個條件,事件發生的機率互相獨立。
在此觀點下,理想的亂數應符合以下分佈
那麼以文字的資訊量切入的話什麼是理想的亂數呢?
我們得先談論何爲「資訊」(information),考慮剛才的例子,爲何我們有辦法解讀出 "what the f*ck" 的含義?首先從單字來看,我們知道 what 按順序出現時可表達出某個意思,換句話說當出現 wha 時,有很高的機率接下來會出現 t;從句子來看,當我們看到 what 知道他是疑問詞,根據文法結構可以預期接下來會出現名詞的機率很高,相反如果出現的不是名詞我們將難以判斷該文句的意義,我們就認爲該句子是隨機而無意義的。
上述過程我們可以發現一件事情,當我們預期某個事件發生的機率很高,而他真的發生的時候,我們獲得的資訊其實沒有變多,也就是說上面這句話裏面事實上有許多部分是多餘的,即便我們將一部分的字元移除仍可以傳達相等的資訊(缺失的部分可以很容易預測),例如 "wat th fk" 即使沒有一個單字拼對我們仍可讀出一樣的訊息,兩個句子每個字元平均所含的資訊量是不相等的,這也是資訊壓縮的基本原理,要怎麼用最少的字元數表達相同的資訊量。
總結來說,當一個事件發生的機率越低,而他真的發生時,我們獲得的資訊會越多,這就是資訊含量 Entropy 的基本想法,Entropy 定義是某個隨機事件平均每個結果發生時所能傳達出的資訊量,公式如下
Entropy 實際上是 Self-information 的期望值,Self-information 即每個隨機事件發生所傳達的資訊量,定義上資訊量與隨機事件發生的機率成反比,且機率爲 1 時資訊量爲 0,根據定義我們發現 log 有這樣的性質,因此
帶入 P 值可以發現 P 越小 I 會越大,符合我們對資訊量的定義。
此外使用 log 還有一個性質:資訊是可加的,兩個獨立事件發生的資訊量為個別資訊量相加。
觀察 Entropy 公式可以發現到,對於一分佈而言,因 ,Entropy 的極大值發生在 時 , 此分佈即爲 uniform distribution,因爲每個事件的發生的機率都一樣,不論發生哪個事件我們都可以獲得最大的資訊量,這就是資訊觀點的亂數,從剛剛文法的例子去想也很直覺,若我們難以從前面的資訊預測接下來會出現的詞,我們更有可能認為該句子是亂數產生的。
上面我們從兩個不同的觀點切入並獲得相同的結果,並有以下結論,隨機具有以下特性
並且我們可以用 Entropy 來量測亂度
在現實世界中是否存在真正理想的亂數,目前仍有爭議,因為古典的科學建立在任何事件發生皆有因果關係之上,如果我們能夠獲取夠全面的資訊的話,就應該可以預測接下來會發生的事情,若存在一事件發生與過去所有狀態無關,則會打破這樣的因果關係;但近代的量子物理開始有發現到一些自然界的隨機性。
儘管如此我們可以透過一些手段,讓亂數雖然是經過一連串確定性的過程產生,卻可在我們使用的範圍內「不可預測」,這就是「偽亂數」(pseudo-random number),產生偽亂數的產生器即為 pseudo-random number generator (PRNG)。
PRNG 的數學描述如下
考慮一函數集合
為一系列檢測一組長度為 n 的序列是否為亂數的統計試驗,稱為 Adversaries,則有一函數
稱為 Generator,試圖欺騙所有 裡面所有的 ,並容許偏差 ,即對於所有 裡面的 , 和 的統計距離不大於 ,其中 為 的 uniform distribution。
Adversaries 的例子可參考 Statistical randomness - Wikipedia#Tests
linux 底下有個命令 ent
可計算一輸入字串的 Entropy。
嘗試計算 linux 內建的 PRNG /dev/random
1 byte char 的大小為 ,則最大的 entropy 為 ,可觀察到這次取出的結果相當接近這個理論值。
輸出的第二的部分為最佳壓縮率計算,這個值是從 entropy 計算而來的。
輸出的第三部分為卡方檢定的結果,卡方中的適合度檢定(Goodness of Fit)可用來檢定資料是否符合某種分佈,我們可以用卡方來檢驗我們的資料是否符合 Uniform distrubution,卡方檢定的 null hypothesis 如下
經由卡方檢定計算出的 p 值若小於設定的信心水準 (如0.05) 表示拒絕此虛無假說,則可宣稱此組資料不符合指定分佈,反之則宣稱無證據顯示此資料不符合該分佈。
當我們拒絕 null hypothesis 時我們明確表示 爲真,但若檢定結果爲不顯著,結論並非「 爲真」,而是「無證據顯示 爲真」DanielChen
以這次執行的結果而言 p 值為 47.82%,離 5% 信心水準相當遙遠,因此判斷這次產生的亂數有可能符合 Uniform distribution。
最後三個部分分別為平均值檢定、蒙地卡羅法計算Pi值、及序列相關係數(可檢驗序列上每個值前後的相關性),也是檢驗該序列是否是亂數的依據。
除了 ent
之外,還有一個很爲人所知的工具叫做 Diehard tests,他是一系列 Randomness test 的集合,最早由 George Marsaglia 開發,之後釋出的 linux 命令 dieharder
還有後續加入其他的亂數測試。
節錄部分執行結果
以下用 JavaScript 簡單寫了一支小程式來計算 Random Number Generator 這個網站的 entropy 以及卡方值,新增一個書籤並貼上貼上以下代碼,名稱任意,進入網站並產生亂數表之後執行剛剛新增的書籤,結果會顯示在 browser console 裡面
執行結果(範圍0~99999,產生1000個)
就 entropy 而言這次產生出來的亂數表距離理想值還有一段距離。
因為卡方分佈的 CDF 不太好實作,這邊只算了卡方值,可用查表的方式查出自由度 99999, 時,,不顯著,無證據說此分佈不均勻。
但這邊有一個問題,取樣的數目可能太少而範圍太大,發生 local randomness 不足的可能很高,調整亂數範圍為 0~99
發現 entropy 與理想值相當接近,表示該亂數產生器產生出來的亂數有一定程度的亂度。卡方檢定部分,, 不顯著,無證據說此分佈不均勻。因此結論此 RNG 通過 entropy 與卡方檢定,我們能在統計上確保一定程度的亂度。
此論文提出一套量測方法與對應原始碼 dudect,用以量測程式執行時間是否能在常數時間 完成,其特點如下
利用 leakage detection test 測試程式是否是 constant time ,優點是在這個方法下不需要硬體模型,分為以下三個步驟進行
先簡介 Student’s t-distribution 就是抽樣下的常態分佈,抽樣越多就會越接近標準常態分佈(因為越接近母體),圖中的 one-tailed test 和 two-tailed test 和 alternative hypothesis 有關,我們只需要看兩組數據是否不一樣,所以用 two-tailed test
alternative hypothesis: "the two timing distributions are not equal"
接著是 Welch’s t-test
t_threshold_moderate
lab0-c
的 Welch's test 測試項目有兩個:
is_insert_tail_const()
: 用來測試將字串加到 Queue 尾端的執行時間是否能在常數時間完成。is_size_const()
: 用來測試取得 Queue 大小時間是否能在常數時間完成。每個測項又細分兩個階段:
Pre-processing: 主要測量待測物 (給定的程式碼) 的執行時間 (CPU cycle),其步驟如下:
fix class
'\0'
則為 8bytes) 論文提及的random class
is_insert_tail_const()
或 is_size_const()
),並記錄執行時間 (CPU cycles)Statistical test: 將所記錄的CPU執行時間 (CPU cycles) 套用如下 Welch's test 公式,用以計算t value。可對照 lab0-c
原始碼的 t_push() 與 t_compute()。其所計算得出 t value 就可用來判斷測試項目是否在常數時間完成。
越接近 0 代表兩組數據的差異越小