C# 的 Random 不够随机
我的目标是获得比使用内置 Random 或加密 RNG 可能实现的更多随机性。
问:如何从随机数生成器中获得更多随机性?
首先,我正在处理 Random 的单个实例。
我正在使用此例程为对象分配随机速度(XNA Vector2):
public static double d2r = Math.PI / 180f;
public static Vector2 rndV2gtHalf(float scaleFactor)
{
double dir = random.NextDouble() * 360 * d2r;
return new Vector2((float)Math.Cos(dir) * scaleFactor, (float)Math.Sin(dir) * scaleFactor);
}
d2r 是度数到弧度转换的因子。出于测试目的,我每秒在屏幕上放置大约 6000 个对象,它们从我的鼠标位置以“随机”方向移动。这是结果
尽管这些物体朝四面八方飞去,但它们似乎是在“摆动”的连接流中这样做的。我猜测摆动是流本身的“箱”内微小随机性的结果。溪流不围绕中心旋转,因此即使摆动,覆盖范围也不完整。
我试图通过使其依赖于 random.NextDouble 的 3 次使用来增加我的速度的随机性。这导致接近 0 度的大片带几乎是空的。除了那条空旷的地带,其余的方向都像以前一样被覆盖了。
public static Vector2 rndV2gtHalf(float scaleFactor)
{
double dir = ((random.NextDouble() + random.NextDouble() + random.NextDouble()) / 3) * 360 * d2r;
return new Vector2((float)Math.Cos(dir) * scaleFactor, (float)Math.Sin(dir) * scaleFactor);
}
显然,这不会产生更多的随机性。
所以,我想也许我在这个过程中过早地组合了随机数,并且通过添加从根本上改变了数字的随机性。所以,在转换为弧度之前,我尝试对其中的一些进行修改。
public static Vector2 rndV2gtHalf(float scaleFactor)
{
double dir = random.NextDouble() * 360;
dir += random.NextDouble() * 360;
dir += random.NextDouble() * 360;
dir += random.NextDouble() * 360;
dir += random.NextDouble() * 360;
dir += random.NextDouble() * 360;
dir %= 360;
dir *= d2r;
return new Vector2((float)Math.Cos(dir) * scaleFactor, (float)Math.Sin(dir) * scaleFactor);
}
这似乎并不比依赖单个 random.NextDouble 更好。
我在某处读到有一个更好的加密随机 num gen,但它似乎不具备产生 Double-s 的本机能力,所以我试图将这些组合在一起。
public static RandomNumberGenerator rng = new RNGCryptoServiceProvider();
public static Vector2 rndV2gtHalf(float scaleFactor)
{
byte[] tokenData = new byte[2];
rng.GetBytes(tokenData);
int myInt = tokenData[1] << 8 + tokenData[0];
double myDouble = ((double)myInt) / 65536f;
double dir = myDouble * 360 * d2r;
return new Vector2((float)Math.Cos(dir) * scaleFactor, (float)Math.Sin(dir) * scaleFactor);
}
这导致粒子的覆盖更加随意。
考虑到两个字节的数据可能不够,我将其增加到 4:
byte[] tokenData = new byte[4];
rng.GetBytes(tokenData);
int myInt = tokenData[3]<<24 + tokenData[2]<<16 + tokenData[1]<<8 + tokenData[0];
double myDouble = ((double)myInt) / 4294967296;
这并没有让它变得更好。
好的。所以也许这与我使用 sin/cos 的方式有关。我将 fn 修改为更像这样:
public static Vector2 rndV2gtHalf(float scaleFactor)
{
return scaleFactor *
new Vector2((float)(random.NextDouble() - 0.5f), (float)(random.NextDouble() - 0.5f));
}
除了这会生成一个方形边缘的流场,它会增长到屏幕的边缘,它看起来不像 sin/cos 尝试那么随机。
我尝试的任何方法似乎都不起作用。所以,重复我的问题,我怎样才能从随机数生成器中获得更多的随机性?