我每隔 10 個值就用模數 (%) 運算符打印一個新行,只是為了保持輸出整齊。來自平均值為 68.0 英寸、標準偏差為 6.0 英寸的正態分布隨機身高通過 Gaussian.NextGaussian2 方法的調用返回,我稍后將對此詳細說明。我通過監控小于 56 英寸或大于 80 英寸的值來跟蹤非正常值。這些值是高于或低于平均值 68.0 英寸兩個標準偏差(6.0 * 2 = 12.0 英寸)的值。據統計,隨機生成值超過平均值兩個正(或負)標準偏差的概率大約有 5%。因此,如果生成 100 個隨機身高(就像我現在這樣),則可以預期約有 5 個非正常值。如果得出的非正常值遠多于或遠少于 5 個,則就需要仔細檢查代碼。請注意,在圖 1 所示的運行示例中,我剛好得到 5 個非正常值,這使我更加確信我的隨機生成的身高數據點實際上是正態分布的。
Box-Muller 算法隱含的原理非常深奧,但結果卻是相當簡單。如果您在 [0,1) 值域內有兩個一致的隨機數字 U1 和 U2(如本專欄中第一部分所述),則您可以使用以下兩個等式中的任一個算出一個正態分布的隨機數字 Z:
Z = R * cos( θ ) 其中,
R = sqrt(-2 * ln(U2)) |
正態值 Z 有一個等于 0 的平均值和一個等于 1 的標準偏差,您可使用以下等式將 Z 映射到一個平均值為 m、標準偏差為 sd 的統計量 X:
X = m + (Z * sd) |
以 NextGaussian 方法實現高斯類的最簡單方法由圖 6 中的代碼表示。
我使用的是 Math.Cos 版本,但我本完全可以輕松地使用 Math.Sin 版本。該實現代碼雖然可行,但效率很低。由于 Box-Muller 算法可利用 sin 或 cos 中的任一個函數計算正態分布的 Z 值,因此我倒不如同時計算兩個 Z 值,保存第二個 Z 值,然后在第二次調用 NextGaussian 方法時可以檢索所保存的值。此類實現方法如圖 7 所示。
盡管該方法可行性很好,但也存在一些低效性。使用 Math.Sin、Math.Cos 和 Math.Log 方法進行計算會降低性能。一種提高效率的巧妙方法是使用數學技巧。如果您檢查一下 R 和 θ 的定義,會發現它們與某單位圓內某隨機點的極坐標相對應。該數學技巧就是計算單位正方形內某隨機點的坐標(避免了調用 Math.Sin 和 Math.Cos 方法)并確定該隨機點是否在單位圓范圍內。如果是這樣,我們就可以使用這組坐標;如果不是這樣,則我們可計算一組新的隨機坐標,然后重試一次。約有 78% 的隨機生成坐標都在單位圓范圍內,這提供了更好的性能,但顯然要影響到清晰性。
圖 8 中例示了單位正方形技巧。Box-Muller 基本算法將選擇一個極坐標為 (R, θ) 并保證在單位圓范圍內的點。您也可以在包圍單位圓的單位正方形內選擇矩形坐標;點 (x1, y1) 在單位圓范圍內,但是點 (x2, y2) 則在單位圓范圍之外。圖 9 說明了單位正方形方法的實現。
圖 8 單位正方形技巧
在軟件測試場景中,性能通常不是主要的考慮因素,因此我所提到的三種實現方法都適用。但在軟件開發中,特別是在進行模擬時,性能就成為一個主要問題。盡管 Box-Muller 算法執行起來既高效又相對簡單,但是也有其他替代算法可生成正態/高斯偽隨機數字。有一種高效的替代方法稱為 ziggurat 方法。
總結
讓我進行一下簡單總結。生成隨機測試用例輸入數據是基本的軟件測試技能。.NET Framework 包含一個 System.Random 類,可用于生成某一特定值域內的統一分布的整數型或浮點型偽隨機數字。需要注意的主要問題就是要確保正確指定值域的端點值。
可使用 Wald-Wolfowitz 檢驗方法來分析包含兩個符號的模式以證明它是隨機生成的模式。您可使用此檢驗方法分析隨機測試用例輸入數據或分析所測試系統的輸出數據。
最佳通用混排算法稱為 Fisher-Yates 算法。它非常簡單并且幾乎不需要使用另一種方法。但即使正確算法中存在一絲微小偏差都可能導致算法看似正確但卻存在重大錯誤。
原文轉自:http://www.uml.org.cn/Test/200611225.htm