2009-10-08 13 views
5

Potrzebuję pseudolosowego generatora, który pobiera numer jako dane wejściowe i zwraca inny numer, który jest powtarzalny i wydaje się losowy.Prosty algorytm pseudolosowy

  • Każdy numer wejścia powinny pasować dokładnie do jednej liczby wyjściowej i vice versa
  • same liczby wejściowych zawsze prowadzić samymi wyjściowych
  • kolejne numery wejściowych, które znajdują się blisko siebie (np. 1 i 2), powinien wywoływać zupełnie inne liczby wyjściowe (np. 1 => 9783526, 2 => 283)

To nie może być doskonałe, tylko tworzyć losowe, ale odtwarzalne dane testowe.

Używam C#.


Napisałem ten zabawny kawałek kodu, który jakiś czas temu wyprodukował coś przypadkowego.

public static long Scramble(long number, long max) 
    { 
    // some random values 
    long[] scramblers = { 3, 5, 7, 31, 343, 2348, 89897 }; 
    number += (max/7) + 6; 
    number %= max; 
    // shuffle according to divisibility 
    foreach (long scrambler in scramblers) 
    { 
     if (scrambler >= max/3) break; 
     number = ((number * scrambler) % max) 
     + ((number * scrambler)/max); 
    } 

    return number % max; 
    } 

Chciałbym mieć coś lepszego, bardziej niezawodnego, pracującego z dowolnym rozmiarem numeru (brak argumentu max).

Czy można to prawdopodobnie rozwiązać za pomocą algorytmu CRC? Lub trochę szurania rzeczy.

+4

Chcesz funkcję skrótu. – phoku

+0

Dup of http://stackoverflow.com/questions/239063 – sbi

+0

@sbi: nie jestem pewien, że jest to dokładny duplikat, biorąc pod uwagę wymóg wyłącznej zgodności między wejściem i wyjściem. Zobacz komentarz 'tanascius' na moją odpowiedź poniżej. – MusiGenesis

Odpowiedz

2

You (być może) można to zrobić łatwo w języku C# za pomocą Random Klasa:

public int GetPseudoRandomNumber(int input) 
{ 
    Random random = new Random(input); 
    return random.Next(); 
} 

Skoro wyraźnie wysiewu Losowo z wejściem, dostaniesz taki sam efekt za każdym razem, biorąc pod uwagę samą wartość wejściowa .

+2

Ale jego pierwszym wymaganiem jest "Każdy numer wejściowy powinien pasować do dokładnie jednego numeru wyjścia i na odwrót" - vice versa nie będzie działać z twoim rozwiązaniem. – tanascius

+0

@tanascius: właściwie nie jestem pewien, czy to * nie pasuje * do tego wymogu, ale nie wiem, jak działa Random pod maską, więc możesz mieć rację. – MusiGenesis

+1

Cóż, testowałem na wejściach od 1 do 10 milionów ... nigdy nie otrzymujesz tego samego wyjścia dwa razy ... więc może to zadziałać. Ale nadal zależy to od wdrożenia i może się zmienić w przyszłości. – tanascius

4

usunąć kod microsoft z tej odpowiedzi, plik kodu GNU jest dużo dłużej, ale w zasadzie nie zawiera tego od http://cs.uccs.edu/~cs591/bufferOverflow/glibc-2.2.4/stdlib/random_r.c:

int32_t val = state[0]; 
val = ((state[0] * 1103515245) + 12345) & 0x7fffffff; 
state[0] = val; 
*result = val; 

dla celów, nasienie jest stan [0] więc miałoby to wyglądają bardziej jak

int getRand(int val) 
{ 
    return ((val * 1103515245) + 12345) & 0x7fffffff; 
} 
+0

Hm, ta informacja o prawach autorskich nieco wbija mi się w oczy.Czy myślisz, że możesz po prostu wkleić ten kod tutaj? – sbi

+0

cóż, nie jestem prawnikiem, ale jest to tylko fragment z pliku, również mówi o prawach autorskich 1985-2001 (teraz jest rok 2009). Jest on również dostępny online w innych miejscach i zostawiłem tekst w pliku z prawami autorskimi. Jeśli ktoś ma z tym problem, mogę usunąć odpowiedź i zastąpić ją GNU. –

+0

To jest Steve Ballmer - twój tyłek jest mój, chłopcze! – MusiGenesis

1

pierwsze dwa przepisy wskazują na stały lub permutacji wejściowe rozstawiony na wejściu, ale trzecia zasada wymaga dodatkowo przekształcać.

Czy istnieją dalsze ograniczenia dotyczące tego, jakie powinny być wyniki, aby kierować tą transformacją? - np. czy istnieje zestaw wejściowy wartości wyjściowych do wyboru?

Jeśli jedynym przewodnikiem jest „no max”, użyję następujących ...

  1. Zastosuj algorytm skrótu do całego wejścia, aby uzyskać pierwszą pozycję wyjściową. CRC może działać, ale dla bardziej "losowych" wyników użyj algorytmu kryptograficznego takiego jak MD5.

  2. Użyj kolejnego algorytmu permutacji (mnóstwo linków w Google) na wejściu.

  3. Powtórz polecenie mieszania, a następnie następne, aż do znalezienia wszystkich wymaganych wyników.

Następny permutacji może być przesadą choć prawdopodobnie można po prostu zwiększyć pierwsze wejście (a może, na przepełnienie, przyrost drugi i tak dalej) przed ponawianie hash.

Do mieszania w stylu kryptograficznym potrzebny jest klucz - po prostu wyprowadź coś z danych wejściowych przed rozpoczęciem.

1

Generator tausworthe jest prosty do wdrożenia i dość szybki. Poniższy pseudokod realizacja ma pełny cykl (2 ** 31 - 1, ponieważ zerowy to stały punkt):

def tausworthe(seed) 
    seed ^= seed >> 13 
    seed ^= seed << 18 
    return seed & 0x7fffffff 

nie wiem C#, ale jestem przy założeniu, że ma XOR (^) i nieco shift (<<, >>) operatorów jak w C.

Ustaw początkową wartość początkową i wywołaj przy pomocy seed = tausworthe(seed).