Generator liczb pseudolosowych ACORN

0

Czy ktoś potrafi zastosować wzór, za pomocą którego zdefiniowano algorytm, na przykład tutaj:

http://www.pureprogrammer.org/java/format_project.cgi/projects/ACORN_PRNG_Test.txt

Albo tutaj na stronie autorów:

http://acorn.wikramaratna.org/concept.html

Na Wikipedii piszą, że to zdaje wszelkie testy losowości i jest szybkie. U mnie oblewa od razu w PractRand.

https://en.wikipedia.org/wiki/ACORN_(PRNG)#cite_note-wwwReferences-9

Ja bym to napisał tak:


M = 2**32

Y = [2173408735,3305678149,965344003,2350408401,3031407883]

def ACORN(Y):
    for i in range(1,5):
        Y[i] = (Y[i-1] + Y[i]) % M
    return Y

for i in range(100):
    Y = ACORN(Y)
    print(Y[4])

Ale tak generowane liczby nie zdają żadnych testów, oblewają niemal natychmiast w PractRand. nawet, gdy zwiększymy modulus do 2**128 i lista będzie miała więcej niż 10 liczb, jak zalecają autorzy. Tymczasem według Wikipedii i tego co rzekomo autorzy opowiadali na konferencjach ich generator daje lepszej jakości wyniki niż Mersenne Twister.

Czy źle rozumiem przedstawiony wzór?

0

Ok, już wiem o co chodzi. Ten generator zdaje testy, gdy użyjemy liczb 128-bitowych i weźmiemy tylko najbardziej znaczące 32 bity:

M = 2**128

Y = [129874338374849931842447800125481114441,208849053888544955861870665807412484259,284101005232733763440229147119070349731,246793457387845104825566841716248400501,127274871851709299003399660516357936791,21568277196533849279833670178041453823,334192045809735254445144277117161070865,15323220607398930464969256528898506211,36073409529507693532181448640008430017,241518437476699427495088190745139153991]

def ACORN(Y):
    for i in range(1,10):
        Y[i] = (Y[i-1] + Y[i]) % M
    return Y

#for i in range(100):
while True:
    Y = ACORN(Y)
    wynik = Y[9] >> 96

Tak może wyglądać przykładowa inicjalizacja. Ale nigdzie na stronie autora nie jest napisane, że trzeba brać najbardziej znaczące bity, ani ile tych bitów. Jeżeli zwracamy liczby zmiennoprzecinkowe i podzielimy wyniki przez modulus, to i tak najmniej znaczące bity są ucinane. Tym niemniej autor pisze, że Y[k] tworzą rzekomo sekwencje liczb pseudolosowych - bez żadnych dodatkowych uwag do tego stwierdzenia.

A na Wikipedii piszą już zupełnie odklejone rzeczy:

Initially, ACORN was implemented in real arithmetic in FORTRAN77,[1] and shown to give better speed of execution and statistical performance than Linear Congruential Generators and Chebyshev Generators.

Jak 10 dodawań może dawać lepsze wyniki, niż jedno mnożenie w generatorze LCG? Nie wydaje mi się, żeby to mogło być szybsze niż LCG. Ponadto 128-bitowy LCG, gdy weźmiemy tylko 32 najbardziej znaczące bity również zdaje wszelkie testy, a jest szybszy i ma znacznie mniejszy stan:


unsigned __int128 LCG(unsigned __int128 LCG_state)
{
    LCG_state = LCG_state * 14647171131086947261 + 12345;
    return LCG_state;
}

int main()
{

    unsigned __int128 LCG_state = 71911;
    uint32_t result;

        while (true)
        {
        LCG_state = LCG(LCG_state);
        
        result = LCG_state >> 96;
        
        //std::cout << result << "\n";
        }
}


0

Wypada chyba opuścić wikipedię i poważniejsze rzeczy przejrzeć:)

1 użytkowników online, w tym zalogowanych: 0, gości: 1