###### tags: `math` `rng` `Public` # Fast RNG 的數學原理 取代模數運算(Mod)的快速替代方案 ## 目的 我們有生成隨機 32 位整數$[0,2^{32}-1]$的亂數產生器, 如何取得N元素中隨機選取一個整數? ```mermaid graph LR; a["x(0,1,2,...,4294967295)"]--"映射方式A(取餘數)"-->b["N(0,1,2...N)"] a--"映射方式B(擴容後相乘後再移位)"-->b ``` ## N屬於2的冪次(N=2,4,8,16,...) 可以藉由位元位移快速取得精確的解 ## Mod模數減少$Xmod(N)$ ```C++ uint32_t reduce(uint32_t x, uint32_t N) { return x % N; } ``` 將亂數產生器產生的隨機量RNG對我們所求的N取餘數。 在範圍內,可視為一個公平的映射。 ### 特點 * 當N不是2的冪次時,會有偏誤(Bias) * N與$2^{32}-1$的數量級越接近,偏誤(Bias)越大 * 使用方法為除法,除法是很昂貴的的算法,比乘法貴很多 ## 快速替代方案 擴容乘積法 $(X\times N)/2^{32}$ ```C++ uint32_t reduce(uint32_t x, uint32_t N) { return ((uint64_t) x * (uint64_t) N) >> 32 ; } ``` 假設x和N是 32 位整數,請考慮 64 位乘積x * N。你有$(X\times N)/2^{32}$。 與模數減少法一樣在範圍內,可視為一個公平的映射。 ### 特點 * 當N不是2的冪次時,會有偏誤(Bias) * N與$2^{32}-1$的數量級越接近,偏誤(Bias)越大 * 使用方法為乘法與位元運算 ## 效能比較 ### CPU 週期數 模數減少法|擴容乘積法 ---|--- modulo reduction|fast range 8.1|2.2 兩者相比,擴容乘積法快了四倍! ## 參考 1. github.com/valyala/fastrand 2. https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/