Deklaracja zmiennej w funkcji

0

Mam funkcję działającą na intach 64-bitowych:

uint64_t next()
{
    k = k + x;
    x = (k | 1) * x;
    return k ^ x;
}

Ale zauważyłem, że działa szybciej, gdy napiszę:

uint64_t next()
{
    uint64_t k = k + x;
    x = (k | 1) * x;
    return k ^ x;
}

W takim przypadku nie mam możliwości zadeklarowania wartości k. Co wówczas właściwie trafia do k? Czy, gdy k już zostanie zainicjowane, to taka funkcja będzie działać tak samo jak w pierwszym przypadku z arytmetycznego punktu widzenia? Czy mimo wszystko może być szybciej wykonywana?

Czy, jeśli nie zależy mi na tym co za liczba trafi początkowo do k (ale w kolejnych powtórzeniach musi być obliczane prawidłowo k = k + x, jak w pierwszym przykładzie), taka implementacja ma sens?

2
Tomasz_D napisał(a):

Co wówczas właściwie trafia do k?

Masz zmienną globalną o tej samej nazwie. Zmeinne globalne są złem, a o jednoliterowej nazwie są zbrodnią

0
Tomasz_D napisał(a):

Ale zauważyłem, że działa szybciej, gdy napiszę:

Pozwolisz, że nie uwierzę? jest skrajnie trudno zmierzyć jakieś nanosekundowe róznice

Po drugie, (o ile by tak było) niemal nigdy nie należy wybierać (pozornie?) większej szybkosci, jeśli kod miałby być nizszej jakości. A kod na zmiennych globalnych jest gorszym kodem.

1

Wszystkie odpowiedzy wyżej to WAT?

Co wówczas właściwie trafia do k?

Śmieci. Niezainicjalizowana wartość. Jest to Undefined behaviour, i może prowadzić do dowolnych błędnych optymalizacji kompilatora. Nie wolno tak robić!!!

Czy, gdy k już zostanie zainicjowane, to taka funkcja będzie działać tak samo jak w pierwszym przypadku z arytmetycznego punktu widzenia?

Nie, kompilator może wykonać dowolne bezsensowne transformacje kodu, bo kod jest błędny, a więc żaden poprawny program by nigdy jej nie uruchomił.

Czy mimo wszystko może być szybciej wykonywana?

Może być. Np. kompilator zauważy, że to błędny kod, i po prostu go usunie (a więc uzyskasz prędkość nieskończoną).

Czy, jeśli nie zależy mi na tym co za liczba trafi początkowo do k (ale w kolejnych powtórzeniach musi być obliczane prawidłowo k = k + x, jak w pierwszym przykładzie), taka implementacja ma sens?

Nie.

Ogólnie, z tego co widzę, gcc -O2 po prostu zakłada, że początkowa wartość k to 0, nigdy nie patrząc co było wcześniej. Ale możesz nie mieć takiego szczęścia. No a tak czy inaczej, nie spełnia to twoich wymagań funkcjonalnych.

2

Pierwsza wersja by się móc kompilować, musi się odnosić do zmiennych globalnych k i x. trochę humoru... :-)
Druga wersja zasłania zmienną globalną zmienną lokalną tworząc zapis, który prowadzi do UB i kopilator ostrzega, że jest coś nie tak: https://godbolt.org/z/7fjoETfdM
Przypisujesz zmienną samą do siebie, to znaczy UB, a to oznacza, że kompilator widząc to może usunąć ten kod i zrobić sporo innych dziwnych rzeczy.

UŻYWAJ -Wall -Wextra -Werror!!!

0

Testowałem to tutaj i mam to w klasie: https://quick-bench.com/q/d3-gHwiIFYY_U1WPmzqaNCeQt4M. Ale twórca SplitMix zrobił coś podobnego tutaj i dlatego zacząłem eksperymentować z moim kodem: https://prng.di.unimi.it/splitmix64.c. Oczywiście ten generator to tylko przykład, wprowadzam tam kilka komplikacji, ale są bez znaczenia dla problemu, o który mi chodzi.

0

Mierzyłem to tutaj: https://quick-bench.com/q/d3-gHwiIFYY_U1WPmzqaNCeQt4M. Sam nie jestem pewien, czy to nie są tylko przypadkowe wahania.

0
enedil napisał(a):

Wszystkie odpowiedzy wyżej to WAT?

Co wówczas właściwie trafia do k?

Śmieci. Niezainicjalizowana wartość. Jest to Undefined behaviour, i może prowadzić do dowolnych błędnych optymalizacji kompilatora. Nie wolno tak robić!!!

Aha, tak właśnie przeczuwałem. Ale w takim razie, czy to można uznać za poprawne:

https://prng.di.unimi.it/splitmix64.c

Czy, gdy k już zostanie zainicjowane, to taka funkcja będzie działać tak samo jak w pierwszym przypadku z arytmetycznego punktu widzenia?

Nie, kompilator może wykonać dowolne bezsensowne transformacje kodu, bo kod jest błędny, a więc żaden poprawny program by nigdy jej nie uruchomił.

Czy mimo wszystko może być szybciej wykonywana?

Może być. Np. kompilator zauważy, że to błędny kod, i po prostu go usunie (a więc uzyskasz prędkość nieskończoną).

Czy, jeśli nie zależy mi na tym co za liczba trafi początkowo do k (ale w kolejnych powtórzeniach musi być obliczane prawidłowo k = k + x, jak w pierwszym przykładzie), taka implementacja ma sens?

Nie.

Ogólnie, z tego co widzę, gcc -O2 po prostu zakłada, że początkowa wartość k to 0, nigdy nie patrząc co było wcześniej. Ale możesz nie mieć takiego szczęścia. No a tak czy inaczej, nie spełnia to twoich wymagań funkcjonalnych.

Ok, czyli porzucam podobne pomysły. Tylko co z tym SplitMixem, czy tam też jest błąd w sztuce? Swoją drogą to jest kod, który przywiódł mi na myśl podobne pomysły, sam bym nie wpadł na to, żeby robić takie rzeczy. Ale w tym kodzie robią. Chyba, że nie dostrzegam różnicy, a różnica jest.

Na marginesie, czy ktoś zdaje sobie na tym forum sprawę z permanentnego, uciążliwego błędu, który nie pozwala na normalną dyskusję, bo co chwilę przy próbie wysłania komentarza lub odpowiedzi wyskakuje "Zbyt wiele prób. Spróbuj za chwilę."?

0

Ok. Co do globalnych zmiennych mieliśmy dyskusję już w jednym wątku na ten temat - unikam ich. Ale ja testowałem to w klasie: https://quick-bench.com/q/d3-gHwiIFYY_U1WPmzqaNCeQt4M. To chyba nie są globalne zmienne?

0

śmiem zaproponować taką wersję -Wall -Wextra -Werror -Werror=return-type

0
Tomasz_D napisał(a):

Aha, tak właśnie przeczuwałem. Ale w takim razie, czy to można uznać za poprawne:

https://prng.di.unimi.it/splitmix64.c

zmienne globalne/statyczne są inicjalizowane na zero, więc to akurat jest ok (z tym, że tutaj słowo static nie oznacza, że to jest zmienna statyczna. Tak by było, gdybyś użył static wewnątrz funkcji). Czym innym jest, że niestety jest to zmienna (pseudo) globalna.

Na marginesie, czy ktoś zdaje sobie na tym forum sprawę z permanentnego, uciążliwego błędu, który nie pozwala na normalną dyskusję, bo co chwilę przy próbie wysłania komentarza lub odpowiedzi wyskakuje "Zbyt wiele prób. Spróbuj za chwilę."?

Nie zdaję sobie z tego sprawy - u mnie nigdy taki błąd się nie pojawiał. Może chcesz go zgłosić na Coyote ?

0
enedil napisał(a):
Tomasz_D napisał(a):

Aha, tak właśnie przeczuwałem. Ale w takim razie, czy to można uznać za poprawne:

https://prng.di.unimi.it/splitmix64.c

zmienne globalne/statyczne są inicjalizowane na zero, więc to akurat jest ok (z tym, że tutaj słowo static nie oznacza, że to jest zmienna statyczna. Tak by było, gdybyś użył static wewnątrz funkcji). Czym innym jest, że niestety jest to zmienna (pseudo) globalna.

A co oznacza static w tym kodzie? A przede wszystkim co ma na celu ten zabieg deklarowania zmiennej w funkcji? Poza tym, jeśli chcemy uruchomić generator, to chyba musimy zainicjować x = jakaś liczba, czyli nie będzie to zero? To wtedy nie będzie globalna zmienna?

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