Widziałem ten generator liczb pseudolosowych do użytku w modułach cieniujących, o których mowa tu i tam w sieci :
float rand(vec2 co){
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}
Jest różnie nazywany „kanonicznym” lub „jednym wierszem, który znalazłem gdzieś w sieci”.
Jakie jest pochodzenie tej funkcji? Czy wartości stałe są tak arbitralne, jak się wydają, czy też jest jakaś sztuka w ich wyborze? Czy jest dyskusja na temat zalet tej funkcji?
EDYCJA: Najstarszym odniesieniem do tej funkcji, z jakim się spotkałem, jest archiwum z lutego 2008 roku , oryginalna strona została usunięta z sieci. Ale nie ma tam więcej dyskusji na ten temat niż gdziekolwiek indziej.
Odpowiedzi:
Bardzo ciekawe pytanie!
Próbuję to rozgryźć podczas wpisywania odpowiedzi :) Najpierw łatwy sposób na zabawę: http://www.wolframalpha.com/input/?i=plot%28+mod%28+sin%28x*12.9898 +% 2B + y * 78,233% 29 + * + 43758,5453% 2C1% 29x% 3D0..2% 2C + y% 3D0..2% 29
Następnie zastanówmy się, co próbujemy tutaj zrobić: Dla dwóch współrzędnych wejściowych x, y zwracamy „liczbę losową”. Teraz nie jest to jednak liczba losowa. Jest tak samo za każdym razem, gdy wprowadzamy te same x, y. To funkcja skrótu!
Pierwszą rzeczą, jaką robi funkcja, jest przejście z 2d do 1d. To nie jest interesujące samo w sobie, ale liczby są tak dobrane, aby się nie powtarzały. Mamy tam również dodatek zmiennoprzecinkowy. Będzie jeszcze kilka bitów od y lub x, ale liczby mogą być po prostu wybrane dobrze, więc robi się mieszanie.
Następnie próbkujemy funkcję sin () z czarnej skrzynki. Będzie to dużo zależeć od wdrożenia!
Wreszcie wzmacnia błąd w implementacji sin () poprzez pomnożenie i pobranie ułamka.
Nie sądzę, żeby to była dobra funkcja skrótu w ogólnym przypadku. Sin () to numerycznie czarna skrzynka na GPU. Powinno być możliwe skonstruowanie znacznie lepszego, biorąc prawie każdą funkcję skrótu i konwertując ją. Najtrudniejsze jest przekształcenie typowej operacji na liczbach całkowitych używanej w haszowaniu procesora w operacje zmiennoprzecinkowe (pół- lub 32-bitowe) lub operacje stałoprzecinkowe, ale powinno być możliwe.
Ponownie, prawdziwym problemem związanym z tym jako funkcją skrótu jest to, że sin () jest czarną skrzynką.
źródło
Źródłem jest prawdopodobnie artykuł: "O generowaniu liczb losowych za pomocą y = [(a + x) sin (bx)] mod 1", WJJ Rey, 22. European Meeting of Statisticians and the 7th Vilnius Conference on Probability Theory and Statystyka matematyczna, sierpień 1998
EDYCJA: Ponieważ nie mogę znaleźć kopii tego dokumentu, a odniesienie do „TestU01” może nie być jasne, oto schemat opisany w TestU01 w pseudo-C:
#define A1 ??? #define A2 ??? #define B1 pi*(sqrt(5.0)-1)/2 #define B2 ??? uint32_t n; // position in the stream double next() { double t = fract(A1 * sin(B1*n)); double u = fract((A2+t) * sin(B2*t)); n++; return u; }
gdzie jedyną zalecaną wartością stałą jest B1.
Zwróć uwagę, że dotyczy to strumienia. Konwersja do 1-wymiarowego skrótu „n” staje się siatką liczb całkowitych. Domyślam się, że ktoś to zobaczył i przekształcił „t” w prostą funkcję f (x, y). Użycie oryginalnych stałych powyżej dałoby:
float hash(vec2 co){ float t = 12.9898*co.x + 78.233*co.y; return fract((A2+t) * sin(t)); // any B2 is folded into 't' computation }
źródło
fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * (co.xy + vec2(43758.5453, SOMENUMBER))
do funkcji, o której mowa w artykule.a
ib
) używanych wielokrotnie, ale mogła zostać użyta w cytowanej pracy.wartości stałe są dowolne, zwłaszcza że są bardzo duże i oddalone o kilka miejsc po przecinku od liczb pierwszych.
moduł powyżej 1 sinusa o wysokiej amplitudzie pomnożony przez 4000 jest funkcją okresową. jest jak roleta okienna lub blacha falista, która jest bardzo mała, ponieważ jest pomnożona przez 4000 i obrócona pod kątem przez iloczyn skalarny.
ponieważ funkcja jest 2-D, iloczyn skalarny powoduje obrócenie funkcji okresowej ukośnie względem osi X i Y. W przybliżeniu o stosunku 13/79. Jest to nieefektywne, możesz osiągnąć to samo, wykonując sinus (13x + 79y), to również da to samo, co myślę, przy mniejszej liczbie matematyki.
Jeśli znajdziesz okres funkcji zarówno w X, jak i Y, możesz próbkować go, aby ponownie wyglądał jak prosta fala sinusoidalna.
Oto jego zdjęcie powiększone na wykresie
Nie znam pochodzenia, ale jest podobny do wielu innych, jeśli użyjesz go w grafice w regularnych odstępach czasu, będzie miał tendencję do tworzenia wzorów mory i możesz zobaczyć, że w końcu znowu się kręci.
źródło
(13x + 79y)
ponieważdot(XY, AB)
zrobi dokładnie to, cox,y dot 13, 79 = (13x + 79y)
Może jest to jednorazowe chaotyczne mapowanie, które mogłoby wyjaśnić wiele rzeczy, ale może też być po prostu dowolną manipulacją dużymi liczbami.
EDYCJA: Zasadniczo funkcja ułamek (sin (x) * 43758.5453) jest prostą funkcją podobną do skrótu, sin (x) zapewnia płynną interpolację grzechu między -1 do 1, więc sin (x) * 43758.5453 będzie interpolacją od - Od 43758,5453 do 43758,5453. Jest to dość duży zakres, więc nawet mały krok w x zapewni duży skok w wyniku i naprawdę duże zróżnicowanie w części ułamkowej. „Ułamek” jest potrzebny do uzyskania wartości z zakresu od -0,99 ... do 0,999 .... Teraz, gdy mamy coś w rodzaju funkcji skrótu, powinniśmy utworzyć funkcję do produkcji hash z wektora. Najprostszym sposobem jest oddzielne wywołanie „hasha” dla x dowolnego składnika y wektora wejściowego. Ale wtedy będziemy mieli pewne symetryczne wartości. Więc powinniśmy pobrać jakąś wartość z wektora, podejście polega na znalezieniu jakiegoś losowego wektora i znalezieniu iloczynu "kropkowego" do tego wektora, zaczynamy: fract (sin (dot (co.xy, vec2 (12,9898,78,233))) * 43758,5453); Ponadto, zgodnie z wybranym wektorem, jego długość powinna być na tyle duża, aby mieć kilka peroidów funkcji „sin” po obliczeniu iloczynu „kropkowego”.
źródło