如何評價一個隨機數算法?我的認爲,一個好的隨機數算法,能提供足夠的安全性和公平性,並擁有優異的性能。java
真隨機數發生器因爲價格昂貴,並無獲得廣泛採用。那麼,僞隨機數就出來了,好比sha1prng。僞隨機數的安全性依賴於種子。怎麼實現sha1prng和其餘的僞隨機數算法,咱們如今不作討論。java和C#都有相應的API,java的SecureRandom和C#的RNGCryptoServiceProvider。咱們就不重複再輪子了。算法
上面的兩個類均可覺得咱們提供僞隨機的字節流。同時java還提供產生安全隨機整數的API了,這裏就不討論java的安全隨機數了。下面說說,怎麼利用僞隨機的字節流產生安全的高強度的隨機整數。數組
有網友是這樣實現,暫且命名爲FastNextInt。安全
public int FastNextInt(int max) { byte[] bs = new byte[4]; generator.GetBytes(bs); int value = BitConverter.ToInt32(bs, 0); value = value % max; if (value < 0) value = -value; return value; }
這種算法能夠快速地獲得一個「隨機」整數,可是這種方法使得在[0,max)範圍內,各整數出現的頻率是不同的。很明顯,前面k=0x100000000/max*max個整數,先使得0~(max-1)中的整數各出現了0x100000000/max次。而後0~(0x100000000-k)再會出現一次。因此容易計算得,第(0x100000000-k+1)~max-1個數出現的機率爲0x100000000/max/0x100000000=1/max;前面第0~(0x100000000-k)個數出現的機率爲(0x100000000/max+1)/0x10000000。其機率比1/max大了1/0x10000000.所以,出現次數多的數就比出現次數少的數多出了約(1/0x100000000)/(1/max)=max/0x100000000的可能。好比,假設max=0x7FFFFFFF;2,3,4....出現了兩次,其餘數只出現了3次。就相對多出了1/2的可能。舉個例子,若是面向21億觀衆抽獎,明顯這樣就顯得不公平了。dom
是否是這樣就無解了?首先回過頭思考一下,多出來的可能等於max/0x100000000。若是把分母擴大會怎麼樣?假如將分母擴大到0x10000000000000000,max在32位的範圍內,多出來的可能約爲幾十億分之一,是否是能夠忽略不計?因而就有了FastNextLongide
public long FastNextLong(long max) { byte[] bs = new byte[8]; generator.GetBytes(bs); long value = BitConverter.ToInt64(bs, 0); value = value % max; if (value < 0) value = -value; return value; }
這樣,既保持了良好的運算性能,又得到更公平的隨機數。性能
有沒有更加公平、安全的隨機數算法。答案是有的,而且是符合數學理論的。因爲咱們的計算機式二進制的,因此只能產生1,2,3,……位的隨機數,也就是說能夠產生0~1,0~3,0~7,0~15,……這種範圍隨機數。每一個數出現的可能只能是1/(2^1),1/(2^2) ,……其實,咱們能夠這樣作,若是咱們要產生0~n的隨機數,咱們先求出K,其中K是知足n<=2^k的k的最小整數值。接着產生一個K位的隨機序列。若是這個序列表示的值屬於0~n,那麼輸出這個數值。在得到輸出的條件下,容易獲得0~n出現的可能性都是相等的。若是這個序列表示的值大於n,那麼再產生一個新數列,循環操做,直到這個序列知足輸出條件。容易獲得,一個序列得到輸出的可能性大於1/2.繼續下一輪循環的可能性小於1/2.根據數學的N次獨立重複試驗機率計算公式,N次沒有得到輸出的可能性小於(1/2)^N。例如,操做10輪後,沒有得到輸出的可能性爲1/1024.又因爲這個機率是指數級減少的,同時,只用到了移位,比較就能夠實現。因此這個算法並不須要多少計算資源就能夠得到輸出。因爲FastNextInt用到了耗時的模除,因此這個算法並不比FastNextInt更耗多少資源。測試
下面是完整的源代碼。ui
using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Text; namespace RNG { public class SecureRandom { private readonly static double DOUBLE_UNIT = 1.0 / (1L << 53); RandomNumberGenerator generator; public SecureRandom(RandomNumberGenerator generator) { this.generator = generator; } //產生bits位的隨機整數 // bits>=1 protected uint Next(int bits) { byte[] bs = new byte[4]; generator.GetBytes(bs); uint x = BitConverter.ToUInt32(bs, 0); return x >> (32 - bits); } //產生bits位的隨機整數 //bits>=1 protected ulong Next2(int bits) { byte[] bs = new byte[8]; generator.GetBytes(bs); ulong x = BitConverter.ToUInt64(bs, 0); return x >> (64 - bits); } protected int BitLength(int x) { int len = 0; while (x > 0) { len++; x >>= 1; } return len; } protected int BitLength(long x) { int len = 0; while (x > 0) { len++; x >>= 1; } return len; } public int NextInt() { return (int)Next(32); } //max>=1,不包括max public int NextInt(int max) { if (max <= 0) throw new ArgumentException("max <= 0"); int len = BitLength(max); uint x = Next(len); while (x >= max) { x = Next(len); } return (int)x; } //不包括max public int NextInt(int min, int max) { return NextInt(max - min) + min; } //max>=1,不包括max public int FastNextInt(int max) { byte[] bs = new byte[4]; generator.GetBytes(bs); int value = BitConverter.ToInt32(bs, 0); value = value % max; if (value < 0) value = -value; return value; } //不包括max public int FastNextIntint(int min, int max) { return FastNextInt(max - min) + min; } public long NextLong() { return ((long)(Next(32)) << 32) + Next(32); } //max>=1,不包括max public long NextLong(long max) { if (max <= 0) throw new ArgumentException("max <= 0"); int len = BitLength(max); ulong x = Next2(len); while (x >= (ulong)max) { x = Next2(len); } return (long)x; } //不包括max public long NextLong(long min, long max) { return NextLong(max - min) + min; } //max>=1,不包括max public long FastNextLong(long max) { byte[] bs = new byte[8]; generator.GetBytes(bs); long value = BitConverter.ToInt64(bs, 0); value = value % max; if (value < 0) value = -value; return value; } //不包括max public long FastNextLong(long min, long max) { return FastNextLong(max - min) + min; } public bool NextBoolean() { return Next(1) != 0; } //此方法是java源碼中拷貝,此算法獲得的浮點數的隨機性未考究 public float NextFloat() { return Next(24) / ((float)(1 << 24)); } //此方法是java源碼中拷貝,此算法獲得的浮點數的隨機性未考究 public double NextDouble() { return (((long)(Next(26)) << 27) + Next(27)) * DOUBLE_UNIT; } //數組長度須要一致 protected bool GreaterThanOrEqual(byte[] a, byte[] b) { //if (a.Length > b.Length) return true; //if (a.Length < b.Length) return false; for (int i = 0; i < a.Length; i++) { if (a[i] > b[i]) return true; if (a[i] < b[i]) return false; } return true;//全等 } protected byte[] Next3(int bits) { int len = (bits + 7) >> 3; byte[] bs = new byte[len]; generator.GetBytes(bs); bs[0] >>= (8 - bits) & 0x7; return bs; } protected int BitLength(byte[] x) { int i = 0; for (; i < x.Length && x[i] == 0; i++) ; return i == 8 ? 0 : BitLength(x[i]) + (x.Length - i - 1) * 8; } public byte[] NextBigInt(byte[] max) { int bitLen = BitLength(max); if(bitLen==0) throw new ArgumentException("max == 0"); byte[] max_ = new byte[(bitLen + 7) >>3]; Array.Copy(max, max.Length - max_.Length, max_, 0, max_.Length); byte[] x = Next3(bitLen); while (GreaterThanOrEqual(x,max_)) { x = Next3(bitLen); } return x; } } }
測試用的源代碼this
using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Text; namespace RNG { class Program { private static void testRandomInt() { RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider(); SecureRandom random = new SecureRandom(rngCsp); Console.WriteLine("===========testRandomInt============"); int max = 300; int[] counter = new int[max]; int total = 10000000; for (int i = 1; i < total; i++) { counter[random.NextInt(max)]++; } foreach (int x in counter) { double diff = (x * max - total) * 100.0 / total; Console.WriteLine(string.Format("{0,10}\t{1}%", x, diff)); } Console.WriteLine("======================="); } private static void testFastRandomInt() { RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider(); SecureRandom random = new SecureRandom(rngCsp); Console.WriteLine("===========testFastRandomInt============"); int max = 300; int[] counter = new int[max]; int total = 10000000; for (int i = 1; i < total; i++) { counter[random.FastNextInt(max)]++; } foreach (int x in counter) { double diff = (x * max - total) * 100.0 / total; Console.WriteLine(string.Format("{0,10}\t{1}%", x, diff)); } Console.WriteLine("======================="); } private static void testRandomLong() { RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider(); SecureRandom random = new SecureRandom(rngCsp); Console.WriteLine("===========testRandomLong============"); Console.WriteLine(random.NextLong(123456789012345678)); Console.WriteLine("======================="); } private static void testRandomBool() { RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider(); SecureRandom random = new SecureRandom(rngCsp); Console.WriteLine("==========testRandomBool============="); Console.WriteLine(random.NextBoolean()); Console.WriteLine("--------------"); int[] counter = new int[2]; int total = 10000000; for (int i = 1; i < total; i++) { counter[random.NextBoolean() ? 1 : 0]++; } foreach (int x in counter) { double diff = (x * 2 - total) * 100.0 / total; Console.WriteLine(string.Format("{0,10}\t{1}%", x, diff)); } } public static void Print(byte[] bs) { foreach (byte b in bs) { Console.Write(string.Format("{0:x2}", b)); } Console.WriteLine(""); } static void Main(string[] args) { testRandomInt(); testFastRandomInt(); testRandomLong(); testRandomBool(); RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider(); SecureRandom random = new SecureRandom(rngCsp); Console.WriteLine("random float:" + random.NextFloat()); Console.WriteLine("random double:" + random.NextDouble()); Console.WriteLine("==========testRandomBigInt 1============="); byte[] max = { 0x00, 0x00,0x11, 0x22, 0x33, 0x44, 0x55}; for (int i = 0; i < 20; i++) { byte[] r = random.NextBigInt(max); Print(r); } Console.WriteLine("==========testRandomBigInt 2============="); byte[] max2 = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; for (int i = 0; i < 20; i++) { byte[] r = random.NextBigInt(max2); Print(r); } Console.Read(); } } }
輸出:
===========testRandomInt============ 33217 -0.349% 33458 0.374% 33367 0.101% 33418 0.254% 33479 0.437% 33358 0.074% 33332 -0.004% 33259 -0.223% 33204 -0.388% 33287 -0.139% 33335 0.005% 33293 -0.121% 33546 0.638% 33104 -0.688% 33673 1.019% 33551 0.653% 33394 0.182% 33132 -0.604% 33465 0.395% 33349 0.047% 33523 0.569% 33544 0.632% 33367 0.101% 33292 -0.124% 32927 -1.219% 33178 -0.466% 33640 0.92% 33476 0.428% 33171 -0.487% 33171 -0.487% 33077 -0.769% 33266 -0.202% 33321 -0.037% 33594 0.782% 33561 0.683% 33226 -0.322% 33140 -0.58% 33426 0.278% 33333 -0.001% 33448 0.344% 33411 0.233% 33356 0.068% 32972 -1.084% 33606 0.818% 33135 -0.595% 33349 0.047% 33087 -0.739% 33231 -0.307% 33385 0.155% 33786 1.358% 33388 0.164% 33485 0.455% 32996 -1.012% 33473 0.419% 33301 -0.097% 33078 -0.766% 33146 -0.562% 33480 0.44% 33205 -0.385% 33440 0.32% 33335 0.005% 33264 -0.208% 33305 -0.085% 33400 0.2% 33227 -0.319% 33078 -0.766% 33179 -0.463% 33205 -0.385% 33422 0.266% 33156 -0.532% 33223 -0.331% 32930 -1.21% 33474 0.422% 33241 -0.277% 33126 -0.622% 33117 -0.649% 33194 -0.418% 33467 0.401% 33277 -0.169% 33384 0.152% 33341 0.023% 33667 1.001% 33333 -0.001% 33139 -0.583% 33335 0.005% 33615 0.845% 33555 0.665% 33518 0.554% 33536 0.608% 33063 -0.811% 33592 0.776% 33602 0.806% 33368 0.104% 33645 0.935% 33289 -0.133% 33401 0.203% 33494 0.482% 33247 -0.259% 33510 0.53% 33592 0.776% 33258 -0.226% 32824 -1.528% 32927 -1.219% 33043 -0.871% 33420 0.26% 33005 -0.985% 33554 0.662% 33627 0.881% 32940 -1.18% 33488 0.464% 33332 -0.004% 33300 -0.1% 33448 0.344% 33493 0.479% 33489 0.467% 32892 -1.324% 33263 -0.211% 33310 -0.07% 33166 -0.502% 33554 0.662% 33397 0.191% 33308 -0.076% 33227 -0.319% 33335 0.005% 33403 0.209% 33337 0.011% 33099 -0.703% 33496 0.488% 33249 -0.253% 33263 -0.211% 33387 0.161% 33399 0.197% 33414 0.242% 33303 -0.091% 33642 0.926% 33433 0.299% 33280 -0.16% 33474 0.422% 32977 -1.069% 33694 1.082% 33363 0.089% 33199 -0.403% 33429 0.287% 33767 1.301% 33147 -0.559% 33634 0.902% 33493 0.479% 33310 -0.07% 33134 -0.598% 33322 -0.034% 33322 -0.034% 33037 -0.889% 33623 0.869% 33197 -0.409% 33403 0.209% 33259 -0.223% 33208 -0.376% 33049 -0.853% 33141 -0.577% 33457 0.371% 33381 0.143% 33011 -0.967% 33221 -0.337% 33097 -0.709% 33179 -0.463% 33115 -0.655% 33412 0.236% 33348 0.044% 33251 -0.247% 33438 0.314% 33209 -0.373% 33278 -0.166% 33498 0.494% 33189 -0.433% 33328 -0.016% 33560 0.68% 33385 0.155% 33224 -0.328% 33594 0.782% 33567 0.701% 33309 -0.073% 33314 -0.058% 33476 0.428% 33328 -0.016% 33410 0.23% 32904 -1.288% 33314 -0.058% 33197 -0.409% 33295 -0.115% 33345 0.035% 33471 0.413% 33354 0.062% 33323 -0.031% 33406 0.218% 33479 0.437% 33417 0.251% 33509 0.527% 33645 0.935% 33466 0.398% 33441 0.323% 33317 -0.049% 33201 -0.397% 33135 -0.595% 33595 0.785% 33323 -0.031% 33037 -0.889% 33579 0.737% 33160 -0.52% 33231 -0.307% 33718 1.154% 33556 0.668% 33452 0.356% 33228 -0.316% 33232 -0.304% 33157 -0.529% 33216 -0.352% 33464 0.392% 33397 0.191% 33217 -0.349% 33467 0.401% 33348 0.044% 33336 0.008% 33367 0.101% 33420 0.26% 33109 -0.673% 33590 0.77% 33350 0.05% 33415 0.245% 33568 0.704% 33330 -0.01% 33415 0.245% 33178 -0.466% 33261 -0.217% 33105 -0.685% 33268 -0.196% 33327 -0.019% 32926 -1.222% 33311 -0.067% 33131 -0.607% 33169 -0.493% 33375 0.125% 33435 0.305% 33060 -0.82% 33472 0.416% 33408 0.224% 33285 -0.145% 33223 -0.331% 33417 0.251% 33169 -0.493% 33608 0.824% 33407 0.221% 33281 -0.157% 33013 -0.961% 33494 0.482% 33717 1.151% 33266 -0.202% 33765 1.295% 33337 0.011% 33302 -0.094% 33603 0.809% 33235 -0.295% 33670 1.01% 33575 0.725% 33336 0.008% 33358 0.074% 33018 -0.946% 33350 0.05% 33284 -0.148% 33275 -0.175% 33494 0.482% 33523 0.569% 33345 0.035% 32958 -1.126% 33685 1.055% 33173 -0.481% 33580 0.74% 33011 -0.967% 33201 -0.397% 33516 0.548% 33203 -0.391% 33108 -0.676% 33422 0.266% 33332 -0.004% 33468 0.404% 33205 -0.385% 33515 0.545% 33154 -0.538% 33366 0.098% 33577 0.731% 33368 0.104% 33381 0.143% 33279 -0.163% 33160 -0.52% 33455 0.365% 32875 -1.375% 33365 0.095% 33417 0.251% 33287 -0.139% 33377 0.131% 33165 -0.505% ======================= ===========testFastRandomInt============ 33538 0.614% 33470 0.41% 33167 -0.499% 33034 -0.898% 33329 -0.013% 33281 -0.157% 33264 -0.208% 33286 -0.142% 33156 -0.532% 33259 -0.223% 33169 -0.493% 33066 -0.802% 33132 -0.604% 33283 -0.151% 33316 -0.052% 33424 0.272% 33112 -0.664% 33509 0.527% 33149 -0.553% 33213 -0.361% 33151 -0.547% 33218 -0.346% 33195 -0.415% 33209 -0.373% 33038 -0.886% 33107 -0.679% 33515 0.545% 33390 0.17% 33475 0.425% 33165 -0.505% 33273 -0.181% 33484 0.452% 33283 -0.151% 33664 0.992% 33616 0.848% 33600 0.8% 33406 0.218% 33383 0.149% 33220 -0.34% 32926 -1.222% 33187 -0.439% 33591 0.773% 33448 0.344% 33520 0.56% 33448 0.344% 33625 0.875% 33255 -0.235% 33346 0.038% 33282 -0.154% 33403 0.209% 33381 0.143% 33652 0.956% 33075 -0.775% 33433 0.299% 33357 0.071% 33302 -0.094% 33628 0.884% 33357 0.071% 33460 0.38% 33125 -0.625% 33703 1.109% 32828 -1.516% 33311 -0.067% 33626 0.878% 33288 -0.136% 33006 -0.982% 33172 -0.484% 33392 0.176% 33244 -0.268% 33347 0.041% 33537 0.611% 33386 0.158% 33232 -0.304% 33320 -0.04% 33461 0.383% 33064 -0.808% 32988 -1.036% 33319 -0.043% 33574 0.722% 33055 -0.835% 33238 -0.286% 33436 0.308% 33488 0.464% 33548 0.644% 33423 0.269% 33193 -0.421% 33348 0.044% 33147 -0.559% 33380 0.14% 33113 -0.661% 33509 0.527% 33464 0.392% 33174 -0.478% 33030 -0.91% 33081 -0.757% 33496 0.488% 33176 -0.472% 33427 0.281% 33304 -0.088% 33082 -0.754% 33138 -0.586% 33477 0.431% 33267 -0.199% 33516 0.548% 33420 0.26% 33099 -0.703% 33208 -0.376% 33456 0.368% 33087 -0.739% 33502 0.506% 33255 -0.235% 33512 0.536% 33098 -0.706% 33095 -0.715% 33330 -0.01% 33091 -0.727% 33480 0.44% 33281 -0.157% 33529 0.587% 33127 -0.619% 33353 0.059% 33066 -0.802% 33503 0.509% 33472 0.416% 33530 0.59% 33482 0.446% 33035 -0.895% 33374 0.122% 33494 0.482% 33309 -0.073% 33577 0.731% 33269 -0.193% 33210 -0.37% 33867 1.601% 33728 1.184% 33459 0.377% 33500 0.5% 33522 0.566% 33602 0.806% 33284 -0.148% 33259 -0.223% 33314 -0.058% 33368 0.104% 33579 0.737% 33619 0.857% 33150 -0.55% 33637 0.911% 33467 0.401% 33354 0.062% 33467 0.401% 33414 0.242% 33390 0.17% 33279 -0.163% 33263 -0.211% 33473 0.419% 33596 0.788% 33208 -0.376% 33170 -0.49% 33539 0.617% 33550 0.65% 33466 0.398% 33326 -0.022% 33350 0.05% 33285 -0.145% 33342 0.026% 33319 -0.043% 33445 0.335% 33533 0.599% 33184 -0.448% 33501 0.503% 33288 -0.136% 33290 -0.13% 33333 -0.001% 33624 0.872% 33045 -0.865% 33096 -0.712% 33269 -0.193% 33145 -0.565% 33185 -0.445% 33408 0.224% 33526 0.578% 33349 0.047% 33178 -0.466% 33502 0.506% 33510 0.53% 33372 0.116% 33062 -0.814% 33779 1.337% 33157 -0.529% 33397 0.191% 33026 -0.922% 33282 -0.154% 33306 -0.082% 33146 -0.562% 33090 -0.73% 33502 0.506% 33488 0.464% 33656 0.968% 33351 0.053% 33379 0.137% 33152 -0.544% 33468 0.404% 33174 -0.478% 33055 -0.835% 33168 -0.496% 33462 0.386% 33172 -0.484% 33327 -0.019% 33037 -0.889% 33233 -0.301% 33697 1.091% 33328 -0.016% 33368 0.104% 33489 0.467% 33708 1.124% 33007 -0.979% 33276 -0.172% 33443 0.329% 33374 0.122% 33187 -0.439% 33103 -0.691% 33489 0.467% 33280 -0.16% 33409 0.227% 32945 -1.165% 33561 0.683% 33138 -0.586% 33640 0.92% 33466 0.398% 33459 0.377% 33366 0.098% 32991 -1.027% 33207 -0.379% 33594 0.782% 33281 -0.157% 33130 -0.61% 33314 -0.058% 33345 0.035% 33431 0.293% 33297 -0.109% 33590 0.77% 33193 -0.421% 33304 -0.088% 33351 0.053% 33235 -0.295% 33142 -0.574% 33263 -0.211% 33482 0.446% 33223 -0.331% 33289 -0.133% 33338 0.014% 33507 0.521% 33394 0.182% 33453 0.359% 33246 -0.262% 33453 0.359% 33539 0.617% 33325 -0.025% 33253 -0.241% 33337 0.011% 33165 -0.505% 33571 0.713% 33623 0.869% 33173 -0.481% 33471 0.413% 33086 -0.742% 33369 0.107% 33115 -0.655% 33343 0.029% 33403 0.209% 32854 -1.438% 33189 -0.433% 33300 -0.1% 33341 0.023% 33441 0.323% 33264 -0.208% 33180 -0.46% 33357 0.071% 33385 0.155% 33345 0.035% 33421 0.263% 33367 0.101% 33401 0.203% 33406 0.218% 33115 -0.655% 33422 0.266% 33607 0.821% 33404 0.212% 33451 0.353% 33230 -0.31% 33178 -0.466% 33461 0.383% 33324 -0.028% 33240 -0.28% 33490 0.47% 32960 -1.12% 33372 0.116% 33466 0.398% 33318 -0.046% 33451 0.353% ======================= ===========testRandomLong============ 89007644488221403 ======================= ==========testRandomBool============= True -------------- 4997827 -0.04346% 5002172 0.04344% random float:0.7498122 random double:0.58139231767367 ==========testRandomBigInt 1============= 06df2c4218 0f47eca524 015f02f9d5 0f1bbf3f04 079e0c47ec 0f11fc561f 111cff258c 00c714f655 0c13b76a76 08cb5865ed 0d24079f32 077954d85f 02fc20247c 042a1ce9e4 0cb20f09e2 01e0c30157 019759a1cc 04916840ae 01bb6903c4 0b06f70539 ==========testRandomBigInt 2============= 05c45b4bfdd10e538a46add39d3d7e 0836f2f2ef3a099f3674570188f41c 07d570c291195e756bea83d57b3fdf 0329ed611034ed5a28bb844d879eba 04fafcd289d51cac801cac4b9d8f14 07f420c929e9bfa4ea2629838b1b6a 0793343227d8dccda7703d15c259f2 039a719df657299bd1110b57e14969 099c6c1a7cc2b026a8727fbc7eb66e 09416bc3497afb3bc55b93aa634bd7 032de0780dc126e5a4d5de90198c7b 017a8bc3ea7d0f43c177e90c7c917b 0c90302f216d055a1ece20654ffe70 024af92f2c29ea4a4c63b27d5d3c07 0f312181d44cc16192632e21b914c2 0f3bd1eae26d73d6a7591b8b73784d 0cc25269624d2fbddd7615424015ee 04ce83e8decaa1b6aa58f3615ae999 02be0a29ded1dd3826ede7100aa138 03798b94c2a391b97325d2d647583a
從中能夠發現,隨機性是獲得保證的。
建議,在通常使用的時候,max比較小的時候能夠採用FastNextInt或者FastNextLong,最好使用後者,這樣max在32位的範圍內,隨機性公平都能獲得保證,其中將long型結果強制轉換成int便可。固然,追求更高安全,更加公平的能夠選擇NextInt和NextLong。
再最後還作了一些拓展,實現了NextBigInt,其中參數max是大整數轉化爲大端序的字節數組。例如0x112233可用大端序字節數組表示爲{0x11,0x220,0x33}。在不少使用了大整數的程序中,RSA和ECC加密中都用到了隨機的大整數,基本思路和這裏的同樣。他們是這樣是作的,計算出隨機整數的上限(max),再計算出max的字節數N。而後產生N個字節的隨機字節數組。而後判斷這個字節數組對應的大整數值是否在max之內。這種實現的隨機性(包括在數學理論上)也是能夠獲得保證的,你們能夠參考上面的分析。可是這種實現的效率過低。假如這個max的最高位所在的字節是1,那麼相應的隨機字節序列的這個字節,出現1或0的機率爲2/128.那麼操做10次,還未獲得合適的隨機字節序列的機率爲(63/64)^10≈0.8543。100次未獲得合適的隨機字節序列的機率爲0.2070。而NextBigInt操做3次就能夠獲得這樣的效果(1/8=0.125)。