Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > pl.comp.programming > #34268 > unrolled thread

Co robi permuted congruential generator XSL-RR-RR? Próbuję zrozumieć scheamt działania.

Started by"osobli...@gmail.com" <osobliwy.nick@gmail.com>
First post2021-01-02 05:28 -0800
Last post2021-01-02 15:45 +0100
Articles 9 — 2 participants

Back to article view | Back to pl.comp.programming


Contents

  Co robi permuted congruential generator XSL-RR-RR? Próbuję zrozumieć scheamt działania. "osobli...@gmail.com" <osobliwy.nick@gmail.com> - 2021-01-02 05:28 -0800
    Re: Co robi permuted congruential generator XSL-RR-RR? Próbuję zrozumieć scheamt działania. Mateusz Viste <mateusz@xyz.invalid> - 2021-01-02 14:45 +0100
      Re: Co robi permuted congruential generator XSL-RR-RR? Próbuję zrozumieć scheamt działania. "osobli...@gmail.com" <osobliwy.nick@gmail.com> - 2021-01-02 06:33 -0800
        Re: Co robi permuted congruential generator XSL-RR-RR? Próbuję zrozumieć scheamt działania. "osobli...@gmail.com" <osobliwy.nick@gmail.com> - 2021-01-02 06:41 -0800
          Re: Co robi permuted congruential generator XSL-RR-RR? Próbuję zrozumieć scheamt działania. Mateusz Viste <mateusz@xyz.invalid> - 2021-01-02 15:49 +0100
            Re: Co robi permuted congruential generator XSL-RR-RR? Próbuję zrozumieć scheamt działania. "osobli...@gmail.com" <osobliwy.nick@gmail.com> - 2021-01-02 07:25 -0800
              Re: Co robi permuted congruential generator XSL-RR-RR? Próbuję zrozumieć scheamt działania. Mateusz Viste <mateusz@xyz.invalid> - 2021-01-02 17:15 +0100
                Re: Co robi permuted congruential generator XSL-RR-RR? Próbuję zrozumieć scheamt działania. "osobli...@gmail.com" <osobliwy.nick@gmail.com> - 2021-01-02 08:50 -0800
        Re: Co robi permuted congruential generator XSL-RR-RR? Próbuję zrozumieć scheamt działania. Mateusz Viste <mateusz@xyz.invalid> - 2021-01-02 15:45 +0100

#34268 — Co robi permuted congruential generator XSL-RR-RR? Próbuję zrozumieć scheamt działania.

From"osobli...@gmail.com" <osobliwy.nick@gmail.com>
Date2021-01-02 05:28 -0800
SubjectCo robi permuted congruential generator XSL-RR-RR? Próbuję zrozumieć scheamt działania.
Message-ID<2149118b-1cf9-4f45-b6a3-7b59a60446c4n@googlegroups.com>
Znalazłem ostatnio generator liczb pseudolosowych, który mnie interesuje:

https://en.wikipedia.org/wiki/Permuted_congruential_generator

Ale nie jestem w stanie zrozumieć kodu, który jest tam podany. To jest zdaje się w języku C:

1. count = (int)(x >> 122)
2. low64 = rotr64((uint64_t)(x ^ (x >> 64)), count)
3. high64 = rotr((uint64_t)(x >> 64), low64 & 63)
4. return (uint128_t)high64 << 64 | low64

Jedyne co rozumiem to ">>", "^" i "&". Ale czym jest "int"? Czy to (int)(x >> 122) mam rozumieć jako mnożenie dwóch liczb w nawiasach? Co robi rotr64 i czym się różni od rotr? Co to jest uint64_t? Co to jest "|" i jako rozumieć (uint128_t)high64 << 64 | low64?

Czy ktoś coś z tego rozumie? Nie znam C i nie jestem pewien, czy to jest kod w C, czy coś jeszcze innego.

[toc] | [next] | [standalone]


#34269

FromMateusz Viste <mateusz@xyz.invalid>
Date2021-01-02 14:45 +0100
Message-ID<20210102144507.535f1472@mateusz>
In reply to#34268
2021-01-02 o 05:28 -0800, osobli...@gmail.com napisał:
> 1. count = (int)(x >> 122)
> 2. low64 = rotr64((uint64_t)(x ^ (x >> 64)), count)
> 3. high64 = rotr((uint64_t)(x >> 64), low64 & 63)
> 4. return (uint128_t)high64 << 64 | low64
> 
> Jedyne co rozumiem to ">>", "^" i "&". Ale czym jest "int"? Czy to
> (int)(x >> 122) mam rozumieć jako mnożenie dwóch liczb w nawiasach?

To zwyczajny casting, tj "włóż wynik x >> 122 do rejestra o szerokości
inta". Głównie służy do tego, żeby kompilator nie krzyczał, że
próbujesz włożyć __uin128_t do inta.

> Co robi rotr64 i czym się różni od rotr?

rotr64 operuje na zmiennych 64-bitowych, a rotr na zmiennych o
szerokości inta. W zależności od platformy może wyjść na to samo.

> Co to jest uint64_t?

Zmienna zawierająca nieujemną liczbę całkowitą o szerokości 64 bitów.

> Co to jest "|" i jako rozumieć (uint128_t)high64 << 64 | low64?

To jest budowanie liczby 128-bitowej z dwóch 64-bitowych "połówek". A
sam "|" to po prostu OR.

> Czy ktoś coś z tego rozumie? Nie znam C i nie jestem pewien, czy to
> jest kod w C, czy coś jeszcze innego.

C, jak najbardziej.


Mateusz

[toc] | [prev] | [next] | [standalone]


#34270

From"osobli...@gmail.com" <osobliwy.nick@gmail.com>
Date2021-01-02 06:33 -0800
Message-ID<04697c4a-729b-4051-a3a0-346ded2aecd7n@googlegroups.com>
In reply to#34269
1. count = (int)(x >> 122)

Czyli "int" to nasza liczba startowa, na której stosujemy ">>"? A może wrzucamy do generatora liczbę x? Skąd wziąć zatem wartość int i czym ona jest?

> rotr64 operuje na zmiennych 64-bitowych, a rotr na zmiennych o 
> szerokości inta. W zależności od platformy może wyjść na to samo.

> > Co to jest uint64_t? 
> 
> Zmienna zawierająca nieujemną liczbę całkowitą o szerokości 64 bitów.

A skąd mam wziąć wartość tej zmiennej? Wstawiam do równania uint64_t, ale ile to ma konkretnie wynosić? A może to:

((uint64_t)(x ^ (x >> 64)

to wcale nie jest mnożenie, tylko chodzi o coś innego? Ja tu widzę pomnóż liczbę uint64_t razy (x ^ (x >> 64).

[toc] | [prev] | [next] | [standalone]


#34271

From"osobli...@gmail.com" <osobliwy.nick@gmail.com>
Date2021-01-02 06:41 -0800
Message-ID<fbd46930-f562-4199-9336-cc021c363e4en@googlegroups.com>
In reply to#34270
> rotr64 operuje na zmiennych 64-bitowych, a rotr na zmiennych o
> szerokości inta. W zależności od platformy może wyjść na to samo.

A jaką szerokość może mieć int? Rozumiem, że większą niż 64 bity? Po co używać tego zamiennie? Rozumiem, że rotr zrobiłoby to samo co rotr64?

[toc] | [prev] | [next] | [standalone]


#34273

FromMateusz Viste <mateusz@xyz.invalid>
Date2021-01-02 15:49 +0100
Message-ID<20210102154922.59e6c404@mateusz>
In reply to#34271
2021-01-02 o 06:41 -0800, osobli...@gmail.com napisał:
> > rotr64 operuje na zmiennych 64-bitowych, a rotr na zmiennych o
> > szerokości inta. W zależności od platformy może wyjść na to samo.  
> 
> A jaką szerokość może mieć int?

wg. ISO 9899-1990, int ma co najmniej 16 bitów. Górnej granicy brak. Na
obecnych platformach to w praktyce 32 albo 64 bity.

> Rozumiem, że większą niż 64 bity?

Być może takie platformy istnieją. Ja się nie spotkałem.

> Po co używać tego zamiennie? Rozumiem, że rotr zrobiłoby to samo co
> rotr64?

Tylko na platformie, na której int ma 64 bity.

Mateusz

[toc] | [prev] | [next] | [standalone]


#34274

From"osobli...@gmail.com" <osobliwy.nick@gmail.com>
Date2021-01-02 07:25 -0800
Message-ID<41a2bd58-3ee9-4872-a80f-3aacb1e7d2c7n@googlegroups.com>
In reply to#34273
Może napiszę jak ja to rozumiem na chłopski rozum.

1. count = (int)(x >> 122)

Weź jakąś 128-bitową liczbę startową X i zrób right shift o 122 miejsca. 6 najbardziej znaczących bitów trafia w miejsce najmniej znaczących i wychodzi nam jakaś mała 6-bitowa liczba. Swoją drogą dlaczego autor wymyślił tego shifta akurat o 122 bity (być może z jakichś powodów daje najlepsze wyniki)?

2. low64 = rotr64((uint64_t)(x ^ (x >> 64)), count)

Oblicz pierwszą połówkę jako low64. Najpierw policz X XOR X >> 64. Wychodzi mi tu 128-bitowa liczba, ale rozumiem, że uint64_t zawęża ją tylko do 64 najmniej znaczących bitów? Teraz liczymy na niej rotr64 z przesunięciem o count.

3. high64 = rotr((uint64_t)(x >> 64), low64 & 63)

Tu liczymy wyższą połówkę. Tutaj otrzymujemy 64-bitową liczbę poprzez X >> 64 i robimy na niej rotr. Nadal nie rozumiem dlaczego nie możemy tu zrobić i zapisać również rotr64? Czy operacja X >> 64 nie zawsze da nam liczbę 64-bitową? Gdyby X było powiedzmy liczbą 84 bitową, to >> 64 zrobi z niej liczbę 20-bitową. Czyli wtedy nie możemy zrobić rotr64 (bo nie mamy 64 bitów)? A właściwie możemy, ale otrzymamy inny wynik, niż rotr na liczbie 20-bitowej. Jedynie takie widzę tu uzasadnienie.

4. return (uint128_t)high64 << 64 | low64

Tutaj rozumiem, że robimy shift na high64 i doklejamy do tego low64? low64 to będą bity najmniej znaczące.

[toc] | [prev] | [next] | [standalone]


#34275

FromMateusz Viste <mateusz@xyz.invalid>
Date2021-01-02 17:15 +0100
Message-ID<20210102171507.40aeb31a@mateusz>
In reply to#34274
2021-01-02 o 07:25 -0800, osobli...@gmail.com napisał:
> Może napiszę jak ja to rozumiem na chłopski rozum.
> 
> 1. count = (int)(x >> 122)
> 
> Weź jakąś 128-bitową liczbę startową X i zrób right shift o 122
> miejsca. 6 najbardziej znaczących bitów trafia w miejsce najmniej
> znaczących i wychodzi nam jakaś mała 6-bitowa liczba.

Zgadza się. I tutaj, zakładając, że count zostało wcześniej zdefiniowane
jako int, kompilator może się poskarżyć "uważaj, bo próbujesz przypisać
zmienną 128-bitową (x) do zmiennej o mniejszej szerokości (count)".
Dlatego programista wykonuje cast wyniku do (int), aby powiedzieć
kompilatorowi "spokojnie, wiem co robię, to naprawdę ma być int".

> Swoją drogą dlaczego autor wymyślił tego shifta akurat o 122 bity
> (być może z jakichś powodów daje najlepsze wyniki)?

To już należałoby jego zapytać. Ew. poczytać publikacje dot. tego
algorytmu.

> 2. low64 = rotr64((uint64_t)(x ^ (x >> 64)), count)
> 
> Oblicz pierwszą połówkę jako low64. Najpierw policz X XOR X >> 64.
> Wychodzi mi tu 128-bitowa liczba, ale rozumiem, że uint64_t zawęża ją
> tylko do 64 najmniej znaczących bitów?

Tak. 64 najbardziej znaczące bity zostają usunięte, za sprawą castu
(castingu? nie mam pewności jak to się mówi po polskiemu) do uint64_t.

> Teraz liczymy na niej rotr64 z przesunięciem o count.

Warto tu zaznaczyć, że rotr64 to nie C. Po nazwie mogę tylko
przypuszczać, co robi, ale dla pełnej jasności należałoby doczytać
dokumentację danej implementacji.

> 3. high64 = rotr((uint64_t)(x >> 64), low64 & 63)
> 
> Tu liczymy wyższą połówkę. Tutaj otrzymujemy 64-bitową liczbę poprzez
> X >> 64 i robimy na niej rotr. Nadal nie rozumiem dlaczego nie możemy
> tu zrobić i zapisać również rotr64?

Też nie wiem. Tym bardziej, że autor wyszczególnił cast do uint64_t, a
prototyp rotr() który podaje mi google wskazuje że rotr() oczekuje
inta. Nie mam pewności, co autor miał na myśli, ale wygląda mi to na
pomyłkę.

> >> Gdyby X było powiedzmy liczbą 84 bitową, to
> >> 64 zrobi z niej liczbę 20-bitową. Czyli wtedy nie możemy zrobić
> >> rotr64 (bo nie mamy 64 bitów)? A właściwie możemy, ale otrzymamy
> >> inny wynik, niż rotr na liczbie 20-bitowej. Jedynie takie widzę tu
> >> uzasadnienie.

Na platformie, na której sizeof(int) == 8, wynik będzie identyczny w
obu przypadkach.

> 4. return (uint128_t)high64 << 64 | low64
> 
> Tutaj rozumiem, że robimy shift na high64 i doklejamy do tego low64?
> low64 to będą bity najmniej znaczące.

Tak. A cast do uint128_t jest tutaj konieczny, bo bez niego high64
by się po prostu wyzerował (wyshiftował).

Mateusz

[toc] | [prev] | [next] | [standalone]


#34276

From"osobli...@gmail.com" <osobliwy.nick@gmail.com>
Date2021-01-02 08:50 -0800
Message-ID<05e470d8-ea32-4cf2-b07d-79bb8d2dd267n@googlegroups.com>
In reply to#34275
Znalazłem coś takiego na stronie autora:

https://www.pcg-random.org/download.html#c-implementation

#if PCG_HAS_128BIT_OPS
inline pcg128_t pcg_output_xsl_rr_rr_128_128(pcg128_t state)
{
    uint32_t rot1 = (uint32_t)(state >> 122u);
    uint64_t high = (uint64_t)(state >> 64u);
    uint64_t low  = (uint64_t)state;
    uint64_t xored = high ^ low;
    uint64_t newlow  = pcg_rotr_64(xored, rot1);
    uint64_t newhigh = pcg_rotr_64(high, newlow & 63u);
    return (((pcg128_t)newhigh) << 64u) | newlow;
}
#endif

Wygląda na to, że chodzi o dwa razy o rotr64 i faktycznie na wikipedii jest błąd lub niedopatrzenie.

[toc] | [prev] | [next] | [standalone]


#34272

FromMateusz Viste <mateusz@xyz.invalid>
Date2021-01-02 15:45 +0100
Message-ID<20210102154555.5cba7085@mateusz>
In reply to#34270
2021-01-02 o 06:33 -0800, osobli...@gmail.com napisał:
> 1. count = (int)(x >> 122)
> 
> Czyli "int" to nasza liczba startowa, na której stosujemy ">>"? A
> może wrzucamy do generatora liczbę x? Skąd wziąć zatem wartość int i
> czym ona jest?

int to nie jest żadna wartość, to tylko informacja dla kompilatora:
"wynik obliczenia (x >> 122) ogranicz do tylu bitów, ile ma normalny
int na tym systemie". Czyli typowo (dziś) 32 albo 64. W tym konkretnym
przypadku chodzi raczej tylko o uniknięcie ostrzeżenia ze strony
kompilatora.

> A skąd mam wziąć wartość tej zmiennej? Wstawiam do równania uint64_t,
> ale ile to ma konkretnie wynosić? A może to:
> 
> ((uint64_t)(x ^ (x >> 64)
> 
> to wcale nie jest mnożenie, tylko chodzi o coś innego? Ja tu widzę
> pomnóż liczbę uint64_t razy (x ^ (x >> 64).

Tak jak wyżej - uint64_t to nie jest zmienna, tylko cast. Tj.
informacja "wynik działania x xor (x shr 64) ogranicz do 64
bitów". Operacja którą podałeś wykonuje XOR na dwóch połówkach
128-bitowej wartości, wynik zapisuje w niższej połówce, a wyższą
połówkę usuwa (właśnie za pomocą castowania do uint64_t).

Mateusz

[toc] | [prev] | [standalone]


Back to top | Article view | pl.comp.programming


csiph-web