我需要得到一个随机生成器,它将两个坐标作为种子并输出一个随机数,对于相同的坐标总是相同的。所以,受到Jon Skeet's GetHashCode implementation的启发,这就是我所做的:
public class SimpleRandom2D
{
public SimpleRandom2D(int _Seed)
{
Seed = _Seed;
}
public SimpleRandom2D()
{
Seed = new Random().Next();
}
readonly public int Seed;
public float Sample(float _X, float _Y)
{
int thisSeed;
unchecked
{
thisSeed = (int) 2166136261;
thisSeed = thisSeed * 16777619 ^ _X.GetHashCode();
thisSeed = thisSeed * 16777619 ^ _Y.GetHashCode();
thisSeed = thisSeed * 16777619 ^ Seed;
}
return 2f * (float) new Random(thisSeed).NextDouble() - 1f;
}
}
我知道创建一个新的Random远非最佳,但我想在得到它之前得到正确的。然而,事实证明它并不是真正正确的:它有时会为具有相同x且y为±1的坐标返回相同的值。该测试始终失败:
[Test]
[Repeat (20)]
public void Sample_IntegerFloats_WithSameXNeighbourY_NotSame()
{
var random = new Random();
var simpleRandom2d = new SimpleRandom2D();
float y = random.Next(); // .Next() returns an integer, which is implicitly converted to a float — hence IntegerFloats in the test title
float x = random.Next();
float value1 = simpleRandom2d.Sample(x, y);
float value2 = simpleRandom2d.Sample(x, y + 1);
Assert.That(value1, Is.Not.EqualTo(value2));
}
相反,这个测试不会失败:
[Test]
[Repeat (20)]
public void Sample_IntegerFloats_WithSameX_NotSame()
{
var random = new Random();
var simpleRandom2d = new SimpleRandom2D();
float x = random.Next();
float value1 = simpleRandom2d.Sample(x, random.Next());
float value2 = simpleRandom2d.Sample(x, random.Next());
Assert.That(value1, Is.Not.EqualTo(value2));
}
为什么会发生这种情况?如何解决?
答案 0 :(得分:2)
事实证明,我的错误与随机性本身无关。我用随机的.Next()
方法生成了一个随机整数浮点数。但是,我忘了虽然.Next()
会产生0到2,147,483,647之间的任何整数,但浮点类型的精度有限,所以当我+ 1
得到一个“邻居”时,我的浮点数是,大多数时间,这么大,实际上并不重要。换句话说,当你这样做时:
float x = new Random().Next();
y = x + 1;
x通常仍然等于y。