kategoria: ANSI C
[#1] [C] rand()%2 nie działa, dziwny bład..
Cześć,
komenda rand()%2 nie działa jak należy, wynikiem jest zawsze 0.
Użyłem wcześniej srand(time(NULL));

Dziwne bo rand()%3 i dalej działa normlanie.

Problem zaczyna się gdy wchodzę do głównej pętli programu
tam gdzie odczytywane są komunikaty okna.
Poza tą pętlą rand()%2 zwraca 0 lub 1..

Zgłupiałem
[wyróżniony] [#2] Re: [C] rand()%2 nie działa, dziwny bład..

@mateusz_s, post #1

Jaki kompilator? Podaj kawałek kodu dla którego to działa źle.
2
[wyróżniony] [#3] Re: [C] rand()%2 nie działa, dziwny bład..

@Rafael/ARMO, post #2

Ok wyjaśniło się.. podziękowania dla Arcziego który wkleił moje pytanie do ChatGPT ;)

jedna z przyczyn może być fakt, że w takiej pętli zbyt szybko wykonujemy polecenie rand() raz po razie z niskim modulo, w tym wypadku jest to 2.

Jak wspomniałem powyżej modulo 2 nie ma problemów

Rozwiązaniem jest użycie wyższego modulo np. 100 i wtedy < 50 to jest 0 a > 50 to jest jeden..

Przyznam nie wiedziałem o tym..
[#4] Re: [C] rand()%2 nie działa, dziwny bład..

@mateusz_s, post #3

To nie ma sensu. Rand() powinno generować zawsze taka samą sekwencję niezależnie jak szybko wywołujesz funkcję.

Na pewno nie masz tego srand() w tej samej pętli?

Ostatnia aktualizacja: 15.08.2024 10:07:58 przez kiero
1
[#5] Re: [C] rand()%2 nie działa, dziwny bład..

@mateusz_s, post #3

Chwila, chwila ...
A co to znaczy że zawsze generuje zero dla rand() % 2. Jak długo to sprawdzałeś ? Przecież istotą losowości jest że może być w takim przypadku i milion zer a potem jedna jedynka, i potem znowu bilion zer. Jeśli ten algorytm wybiera tylko parzyste liczby przez ileś tam początkowych losowań to zawsze będzie zero w Twoim przypadku. To zależy jaki jest rozkład. Ty za pomocą "powyższego rozwiązania" zmieniłeś rozkład i tyle, tylko czy to jest aby na pewno to co chcesz osiągnąć. Bo jeśli algorytm "losuje" z zakresu 2^31 to częściej będziesz miał wartość 1.

PS: zamiast rand() % 2 ja bym użył rand() & 1 ale to tak na marginesie.
[#6] Re: [C] rand()%2 nie działa, dziwny bład..

@kiero, post #4

Na pewno nie masz tego srand() w tej samej pętli?

Ten mistrzowski numer wykonywałem wiele razy w moich "programikach" i zawsze sobie tłumaczyłem, że widocznie tak losuje :D
[#7] Re: [C] rand()%2 nie działa, dziwny bład..

@asman, post #5

Srand() jest w funkcji init() wykonuje ją tylko raz - zresztą zmieniałem jej położenie zeby posprawdzać i nie było zmian.

Niestety tak jak napisałem rand() %2 zwracał tylko i zawsze 0, zamiast 0 lub 1. Wynik albo wyświetlałem sobie albo było to widoczne w ruchu czy też braku ruchu obiektów.

Poza pętla główną dzialalo.

Sprawdzę jeszcze rand()&1
[#8] Re: [C] rand()%2 nie działa, dziwny bład..

@mateusz_s, post #7

Napisz sobie mały program, który wywala rand() na wyjście w pętli powiedzmy 50 tysięcy razy, przekieruj wyjście do pliku i podejrzyj sobie plik, zobaczysz co daje rand() w Twoim przypadku. Jeśli wszystkie wartości będą parzyste to masz odpowiedź dlaczego jest zero.
I wklej ten kawałek kodu gdzie masz ten rand() % 2, bo być może robisz jakiś błąd typu złe priorytety działań.

Dygresja.
Bo czasami gówniana pomyłka w ifie kosztuje wiele godzin szukania co nie jest halo. Na przykład:
if (losuj() = 0)
{
  //...
}
[#9] Re: [C] rand()%2 nie działa, dziwny bład..

@asman, post #5

Jeśli ten algorytm wybiera tylko parzyste liczby przez ileś tam początkowych losowań to zawsze będzie zero w Twoim przypadku


To trochę chyba słaby ten algorytm pseudolosowy :D. Nie wiem jak Amiga generuje liczby losowe ale w starych komputerach ciężko chyba było o prawdziwą losowość.
[#10] Re: [C] rand()%2 nie działa, dziwny bład..

@asman, post #6

Myślisz że dlaczego zasugerowalem:)

Dlatego wolę własną implementacje która ma jakiś własny kontekst.nie ma problemu z mieszaniem wywołań. I to też polecam zrobić.

Ostatnia aktualizacja: 15.08.2024 11:59:29 przez kiero
1
[#11] Re: [C] rand()%2 nie działa, dziwny bład..

@bfgmatik, post #9

Pseudolosowosc to nie prawdziwa losowosc:)
3
[#12] Re: [C] rand()%2 nie działa, dziwny bład..

@mateusz_s, post #7

Zerknij jeszcze tu: https://stackoverflow.com/questions/2129705/why-is-rand-anything-always-0-in-c
Jedno z rozwiązań: Problem solved! I wasn't using #include <ctime> when I seeded the random number generator! Thanks a lot!
[#13] Re: [C] rand()%2 nie działa, dziwny bład..

@mateusz_s, post #7

Sprawdź może jeszcze, czy czasami nie wywołuje się srand(0). Zobacz tez wynik funkcji time().

Wartość zero jako ziarno generatora w większości przypadków będzie wyrzucało tylko wartości 0.

Taki generator nazywa się multiplikatywnym.
[#14] Re: [C] rand()%2 nie działa, dziwny bład..

@asman, post #8

if (losuj() = 0)
{
  //...
}

Oj tak, takie rzeczy można przeoczyć nawet kilka razy analizując fragment kodu (chociaż tutaj bardziej pasowałby przykład z przyrównaniem do zmiennej, a nie funkcji).

Na szczęście dzisiejsze kompilatory bardzo krzyczą gdy w warunku jest =, a nie ==. Chociaż akurat GCC 10, którego używam pod MorphOS całkowicie to toleruje. Ale mój kod prawie codziennie jest też budowany w nowym Xcode dla macOS, a ten już wytyka takie miejsca i od razu rzucają się w oczy.

Ja ostatnio przestałem używać wykrzynika tylko przyrównuję do 0:
if (funkcja()==0)

zamiast
if (!funkcja())

bo wraz z pogarszającym się wzrokiem coraz częściej taki wykrzyknik zlewał mi się z nawiasem i dwa razy straciłem sporo czasu na odkrycie przyczyny problemu, która była oczywista... gdybym ten wykrzynik widział. W ferworze walki z problemem albo w twórczym szale człowiek często widzi to co chce widzieć, a nie to co powinien. Czasem nawet okulary czy większe fonty nie pomagają. Mózg wie swoje i już!

Ostatnia aktualizacja: 15.08.2024 22:06:40 przez MDW
1
[#15] Re: [C] rand()%2 nie działa, dziwny bład..

@MDW, post #14

żeby nie było - przypisanie wartości do wywołania funkcji zawsze skończy się błędem w c/cpp. W przypadku zmiennej, nowsze wersje gcc emitują ostrzeżenie. Warto mieć włączone -Werror co by kompilator traktował warningi jako errory.

A co do niewidoczności wykrzyknika - może wypadałoby zainwestować w jakiś lepszy schemat kolorowania składni, co by operatory miały inny kolor niż nawiasy. Albo fonta zwiększyć. ;)

Ostatnia aktualizacja: 15.08.2024 22:38:48 przez teh_KaiN
1
[#16] Re: [C] rand()%2 nie działa, dziwny bład..

@asman, post #8

zrobiłem testy,
w załączonym kodzie:

- time(NULL) zwraca dobrze - czyli rosnący czas
- samo rand() - też zwraca jakies wartości rózne
- rand()%2 jak poprzednio zwraca - ALBO tylko 0 ALBO tylko 1 (w zależności po uruchomieniu),
- rand()%3 zwraca prawislowo czyli caly czas cos ze zbioru { 0,1,2}

kompiluje na gcc od Bebbo

kod:
void    SYS__run(void)
{
    // Signal mask for window.
    ULONG signal_mask = ( 1 << SYS__window->UserPort->mp_SigBit );

    char debug_string[32];
    
    UBYTE current_buffer = 0;

     srand(time(NULL));


    // Enter main loop.
    while (G_io__prefs.is_loop)
    {  
        // Enter Window Message Loop - handle messages and events.
	    if(SetSignal(0L, signal_mask) & signal_mask)
	    {
		    struct IntuiMessage	*imsg;

            while( imsg = (struct IntuiMessage *)GetMsg(SYS__window->UserPort) )
            {
                switch (imsg->Class)
                {
                    case IDCMP_MOUSEMOVE:
                    break;

                    case IDCMP_RAWKEY:
                    break;
                }
                ReplyMsg((struct Message *)imsg);
            }       
	    }  

        // If using AGA make c2p conversion to the output buffer and display.
        if (SYS__is_aga) 
        {
            // Rendering the game.
            G_run();

            // Chunky to planar conversion.
            c2p1x1_8_c5_040(G_io__prefs.view_buffer, SYS__buffer[current_buffer]->sb_BitMap->Planes[0]);

            // Swap Buffers with sync.
            if (G_io__prefs.is_sync)
            {
                    if (!SYS__safetochange)
                    {
                        while (!GetMsg(SYS__display_port)) WaitPort(SYS__display_port);
                        SYS__safetochange = TRUE;
                    }


                if (ChangeScreenBuffer(SYS__screen, SYS__buffer[current_buffer])) 
                {
                    SYS__safetochange = FALSE;
                }
            }

            // Switch buffers.
            current_buffer ^= 1;  
        }
        else
        {
            // Puting into screen display the otherone bitmap.     
            SYS__screen->RastPort.BitMap = SYS__buffer[current_buffer^1]->sb_BitMap;
            SYS__screen->ViewPort.RasInfo->BitMap = SYS__buffer[current_buffer^1]->sb_BitMap;

            // Sync with the monitor.
            if (G_io__prefs.is_sync)
            {
                RethinkDisplay();
            }

            // Setting the game output buffer adress into one of the system bitmaps.
            // Now the geme will render directly into one of the system bitmaps.
            G_io__prefs.view_buffer = SYS__buffer[current_buffer]->sb_BitMap->Planes[0];
            
            // Rendering the game.
            G_run();

            // Switch buffers.
            current_buffer ^= 1;  
        }

        // Show some debug info.
        if (G_io__prefs.is_debug)
        { 
      
            sprintf(debug_string, "fps: %d  dt: %.4f  sync: %d", rand()%2, G_io__prefs.delta_time, G_io__prefs.is_sync);
            Move(SYS__window->RPort, 0,20);
            Text(SYS__window->RPort, (CONST_STRPTR)debug_string, strlen(debug_string));
        }
    }
}


to rozwiązanie daje rade
int a = ((rand()%20) < 10);

wiec po prostu zostawie tak..




Ostatnia aktualizacja: 16.08.2024 11:42:04 przez mateusz_s

Ostatnia aktualizacja: 16.08.2024 11:42:12 przez mateusz_s
[#17] Re: [C] rand()%2 nie działa, dziwny bład..

@teh_KaiN, post #15

żeby nie było - przypisanie wartości do wywołania funkcji zawsze skończy się błędem w c/cpp.

Tak tak, to na pewno. Dlatego napisałem, że lepszym przykładem byłoby przyrównanie do zmiennej.

Warto mieć włączone -Werror co by kompilator traktował warningi jako errory.

A to ciekawe, bo u mnie GCC 10 (które przecież bardzo stare nie jest) nie pokazuje tutaj warninga. Muszę popatrzeć.

A co do niewidoczności wykrzyknika - może wypadałoby zainwestować w jakiś lepszy schemat kolorowania składni, co by operatory miały inny kolor niż nawiasy. Albo fonta zwiększyć. ;)

Font lekko zwiększony, okulary też sporo pomogły. Ale rzeczywiście muszę pomyśleć o modyfikacji kolorowania składni, bo tutaj aż prosi się o inny kolor. OK

Ostatnia aktualizacja: 16.08.2024 13:26:50 przez MDW
[wyróżniony] [#18] Re: [C] rand()%2 nie działa, dziwny bład..

@mateusz_s, post #16

int a = ((rand()%20) < 10);


A tak nie prosciej:

int a = ((rand()%20) & 1);
1
[#19] Re: [C] rand()%2 nie działa, dziwny bład..

@Phibrizzo, post #18

Kompilator GCC od Stefana Franke (Bebbo) optymalizuje resztę z dzielenia przez potęgę liczby 2.

Zobaczyłem w jego Compiler Explorer że wychodzi wtedy troszkę dziwny kod ze sprawdzaniem czy liczba jest ujemna.

Normalnie (dla pozostałych liczb) GCC wywołuje funkcję mod() do policzenia tej reszty.

Moim zdaniem coś w tym kierunku trzeba poszukać.

Można sprawdzić tak jak zasugerował Asman i Ty właśnie konstrukcję rand() & 1.

Ostatnia aktualizacja: 16.08.2024 16:58:39 przez Hexmage960
1
[#20] Re: [C] rand()%2 nie działa, dziwny bład..

@mateusz_s, post #16

Dzięki za wklejenie kodu.
Mi chodziło o taki przykładzik
#include <stdio.h>
#include <stdlib.h> 
#include <time.h>

int main(void)
{
	char debug_string[32];

	srand(time(NULL));

	for (int i = 0; i < 20; ++i)
	{
		sprintf(debug_string, "fps: %d  \n", rand() & 1);
		printf("%s", debug_string);
	}

	return 0;
}


Kompilowałem skrośne pod vbcc i wynik są zgodne z oczekiwaniami, czyli i zera i jedynki.

@kiero

Dlatego wolę własną implementacje która ma jakiś własny kontekst.nie ma problemu z mieszaniem wywołań. I to też polecam zrobić.

O to to.

@MDW
Jeśli chodzi o wykrzyknik, to widziałem patenty że ktoś robił po prostu trzy wykrzykniki zamiast jednego, by było to widoczne dla niego. Ja to pewnie bym miał problem typu czy na pewno są trzy i czy czasem z prędkości nie zrobię dwa albo cztery :D
1
[#21] Re: [C] rand()%2 nie działa, dziwny bład..

@MDW, post #14

Język C ma tę własność, że możemy stosować odstępy między "tokenami" w dowolny sposób.

Polecam Ci zatem, drogi kolego, zastosować odstęp dla większej czytelności kodu.

Ja też to stosuję. Przy czym zaczerpnąłem taki styl z kodu źródłowego systemu gier tekstowych Adventure Definition Language z lat 80.

Przykład:

if( ! funkcja() )

Wtedy ten wykrzyknik będzie bardziej widoczny.
[#22] Re: [C] rand()%2 nie działa, dziwny bład..

@MDW, post #17

@MDW Być może potrzebujesz -Wextra.

@mateusz_s sprawdź czy rand() % 2 również Ci zawsze zwraca zero jak wyłączysz bebbo-optymalizatory (parametr -fbbb=-) a jak to nie pomoże, to możesz sprawdzić na -O0. Tak czy inaczej pokusiłbym się o zgłoszenie tego do Bebbo, po co ma wisieć bug jak można to poprawić. Być może też optymalizator dostaje czegoś do głowy i uznaje, że może sobie cache'ować z jakiegoś powodu wynik akurat tej operacji. Możesz spróbować napisać w tej swojej pętli gdzieś "volatile int rand_result = rand() % 2;" i zobaczyć czy printowanie rand_result też będzie miało zawsze tę samą wartość.

Ostatnia aktualizacja: 17.08.2024 22:44:25 przez teh_KaiN
3
[#23] Re: [C] rand()%2 nie działa, dziwny bład..

@teh_KaiN, post #22

słusznie, zerknie jeszcze wieczorem i dam znać..
[#24] Re: [C] rand()%2 nie działa, dziwny bład..

@teh_KaiN, post #22

sprawdzilem te pomysły, ale nie było róznicy,
rand()%2 zawsze zwracał albo tylko 0 albo tylko 1,
napisałem do bebbo w oficjalnym wątku na eab..
[#25] Re: [C] rand()%2 nie działa, dziwny bład..

@mateusz_s, post #24

Chyba lepiej zgłaszać na githubie issue .. ja tak robiłem jak coś mu zgaszałem.
https://github.com/bebbo/amiga-gcc/issues
1
[#26] Re: [C] rand()%2 nie działa, dziwny bład..

@Rafael/ARMO, post #25

zglosilem
1
[#27] Re: [C] rand()%2 nie działa, dziwny bład..

@Rafael/ARMO, post #25

Bebbo wprowadzil pewne zmiany i podal też dodatkowy sposób do testu
https://github.com/bebbo/amiga-gcc/issues/404

musialbym zacaignac nową wersję zeby przetestowac
2
[#28] Re: [C] rand()%2 nie działa, dziwny bład..

@mateusz_s, post #27

No i super. Bebbo należą się ogromne brawa, ... mi kiedyś dorobił/poprawił coś wstępnie stwierdził "nie da się":)
2
Na stronie www.PPA.pl, podobnie jak na wielu innych stronach internetowych, wykorzystywane są tzw. cookies (ciasteczka). Służą ona m.in. do tego, aby zalogować się na swoje konto, czy brać udział w ankietach. Ze względu na nowe regulacje prawne jesteśmy zobowiązani do poinformowania Cię o tym w wyraźniejszy niż dotychczas sposób. Dalsze korzystanie z naszej strony bez zmiany ustawień przeglądarki internetowej będzie oznaczać, że zgadzasz się na ich wykorzystywanie.
OK, rozumiem