如何评价一个随机数算法?个人认为,一个好的随机数算法,能提供足够的安全性和公平性,并拥有优异的性能。
真随机数发生器由于价格昂贵,并没有得到普遍采用。那么,伪随机数就出来了,比如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亿观众抽奖,明显这样就显得不公平了。
是不是这样就无解了?首先回过头思考一下,多出来的可能等于max/0x100000000。如果把分母扩大会怎么样?假如将分母扩大到0x10000000000000000,max在32位的范围内,多出来的可能约为几十亿分之一,是不是可以忽略不计?于是就有了FastNextLong
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更耗多少资源。
下面是完整的源代码。
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;
}
}
}
测试用的源代码
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)。
来源:oschina
链接:https://my.oschina.net/u/256033/blog/797104