2014-11-10 6 views
1

Мне нужно было получить случайный генератор, который взял бы в двух координатах как семя и вывел бы случайное число, всегда одинаковое для тех же координат. Так, вдохновленный 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 и у которых ± 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)); 
    } 

Почему это происходит и как я могу это исправить?

+4

Это не «случайный». Похоже, вы хотите Хешировать двумерную координату. –

+0

Возможно, вы правы - правильный хэш, сам, случайный относительно его семени. Тем не менее, мне нужно было создать его наряду с другими алгоритмами шума, которые будут опираться на него (шум Perlin и т. Д.), Поэтому я решил использовать слово «Random» для ясности. –

+1

Еще один момент: как вы можете проверить параметр 'int _X' с помощью аргумента' float x'? Мы смотрим на настоящий код или нет? –

ответ

2

Оказывается, моя ошибка не имела никакого отношения к случайности. Я сгенерировал случайный целочисленный float с методом .Next() Random. Тем не менее, я забыл, что в то время как .Next() приведет к любому целому числу от 0 до 2,147,483,647, тип float имел ограниченную точность, поэтому, когда я сделал + 1, чтобы получить «сосед», мой поплавок в большинстве случаев был настолько большим, что он Фактически. Другими словами, когда вы это делаете:

float x = new Random().Next(); 
y = x + 1; 

x обычно по-прежнему равен y.

+1

Но это не единственная проблема с этим кодом. Вы хотите «детерминированную случайность», поэтому можете (должны) полностью исключить случайный экземпляр и просто написать простую (Хеширующую) функцию. –

Смежные вопросы