logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

C++: Jak uniknąć powtarzania się liczb losowych przy użyciu rand()?

laneczka 08 Lis 2005 14:22 80891 18
REKLAMA
  • #1 1965045
    laneczka
    Poziom 1  
    Posty: 1
    zwykle generuje liczby losowe poprzez uzycie funkcji rand(). jednak w kazdym odpaleniu programu funkcja ta daje taki sam zestaw liczb. jak tego uniknac?
  • REKLAMA
  • REKLAMA
  • #3 1965513
    Mystic Vintage
    Poziom 12  
    Posty: 96
    Pomógł: 4
    Ocena: 5
    Przed instrukcją losowania dopisz Randomize(); powinno zwiększyć przypakowość

    pzdr
  • #4 1973350
    one_eddie
    Poziom 25  
    Posty: 973
    Pomógł: 62
    Ocena: 14
    Mystic Vintage napisał:
    Przed instrukcją losowania dopisz Randomize(); powinno zwiększyć przypakowość

    pzdr


    To co podales to jesli dobrze pamietam to Borlando-wskie rozszezenie (wraper na srand, kolejne to pewnie Random czyli zastepnik rand), ktorych nie warto pamietac.

    To co podal MarekCz jest standardem i tego warto uzywac.
  • #5 3230559
    deavt
    Poziom 12  
    Posty: 49
    Pomógł: 1
    Ocena: 5
    Macie racje co do procedury rand(), ale generuje ona liczbę losową na podstawie czasu. Jeśli wygeneruje się kilka liczb w tej samej sekundzie będą one takie same.
    A jak zrobić żeby w jednej sekundzie wylosować wieke różnych liczb?
  • REKLAMA
  • #6 3230620
    one_eddie
    Poziom 25  
    Posty: 973
    Pomógł: 62
    Ocena: 14
    deavt napisał:
    Macie racje co do procedury rand(), ale generuje ona liczbę losową na podstawie czasu. Jeśli wygeneruje się kilka liczb w tej samej sekundzie będą one takie same.
    A jak zrobić żeby w jednej sekundzie wylosować wieke różnych liczb?


    Zalezy na jakiej dokladnosci ci zalezy. Sa funkcje ktore zwracaja czasy nie mniejsze niz 1/10 ms i ile sie nie myle. Mozna by je wykrozytsac do generowania twoich liczb. Wystarczy w zrodlach rand zwykly czas zamienic na ten. Mozna by dodac jeszcze kilka rzeczy ktore wprowadzily by losowosc. Np stan jakichs ogolnie dostepnych portow.
  • #7 3231086
    Sam Sung
    Poziom 33  
    Posty: 2013
    Pomógł: 227
    Ocena: 583
    deavt napisał:
    Macie racje co do procedury rand(), ale generuje ona liczbę losową na podstawie czasu. Jeśli wygeneruje się kilka liczb w tej samej sekundzie będą one takie same.
    A jak zrobić żeby w jednej sekundzie wylosować wieke różnych liczb?

    Nieprawda - rand() losuje liczbę na podstawie seeda (ziarna) i po wylosowaniu uaktualnia ziarno. Nie zależy to od żadnego licznika czasu. Oczywiście ileś tam kolejnych liczb może wypaść takich samych, ale jest to mało prawdopodobne i zazwyczaj wychodzą różne.
    Seeda ustawia się raz na początku przed generowaniem ciągu liczb pseudolosowych. Zazwyczaj ustawia się go na wartość time(NULL) i to ta funkcja zwraca czas z dokładnością do jednej sekundy. Problem powstaje więc dopiero wówczas, gdy odpalamy naraz wiele równoległych procesów, które na początku ustawiają sobie tego samego seeda i generują przez to identyczne ciągi liczb pseudolosowych.
  • #8 3885726
    vrock
    Poziom 11  
    Posty: 5
    Dla ścisłości - funkcja rand ma mniej więcej taką końcówkę:
      ...
      /* x jest wygenerowaną liczbą pseudolosową */
      srand(x);
      return x;
    }


    Z tego powodu dla konkretnego ziarna początkowego, funkcja rand() generuje identyczny ciąg liczb pseudolosowych.
    Jak widać wylosowana liczba daje początek następnej, ta - następnej.. I tworzy się taki wielki cykl.

    Nie znam dokładnie algorytmu wyliczania kolejnej liczby z ziarna, ale prawdopodobnie wylosowane ziarno powtarza się dokładnie co 2^32 wywołań rand(). Gdyby było inaczej, niektóre wartości ziarna byłyby nie do uzyskania, a to przecież niesprawiedliwe, prawda? ;-)
  • #9 3886083
    ed-ek
    Poziom 34  
    Posty: 1814
    Pomógł: 275
    Ocena: 42
    Masz przykład losowania 5 liczb z powtórzeniami z 10 liczb:
    (generuje liczby>0,bo :k=rand()%10+1;)
    #include <time.h>
    #include <conio.h>
    #include <iostream.h>
    int main()
    {
    int i,k;
    time_t t;
    srand((unsigned) time(&t));
    i=0;
    while (i<=5 )
    {
    k=rand()%10+1;
    cout<<k<<" ";
    i++;
    }
    getch();
    }
  • REKLAMA
  • #10 3887036
    Sam Sung
    Poziom 33  
    Posty: 2013
    Pomógł: 227
    Ocena: 583
    ed-ek napisał:
    Masz przykład losowania 5 liczb z powtórzeniami z 10 liczb:

    Można wiedzieć, do kogo to jest skierowane?
  • #11 3887425
    ed-ek
    Poziom 34  
    Posty: 1814
    Pomógł: 275
    Ocena: 42
    A do autora pierwszego postu. Widać na przykładzie jak należy napisać program aby za każdym odpaleniem generował różne liczby. Akurat kiedyś miałem taki napisany.
    Sam Sung: nie rozumiem pytania (zarzutu?).
  • #12 6076618
    Raffal_1988
    Poziom 10  
    Posty: 10
    a podpowie mi ktoś jak ustawić przedział liczb w ktore moga być losowe ?
    Chodzi mi aby ustawić takze dolny przedział i musi on być ujemny

    
    for ( a =0 ; a<i ; a++)
      {
    z[a]= rand()% 10 ;
    
      cout<<" "<<z[a];
      }
    
    for ( a =0 ; a<p ; a++)
      {
      z[a]=0;  
      }
    
    a = 0;
    
    
  • #13 6076675
    one_eddie
    Poziom 25  
    Posty: 973
    Pomógł: 62
    Ocena: 14
    Rand zwraca wartosci od 0..RAND_MAX czyli jesli podzielisz rand przez RAND_MAX dostaniesz przedzial 0..1. Z tym juz sobie chyba poradzisz?
  • #14 6076707
    Raffal_1988
    Poziom 10  
    Posty: 10
    a jak otrzymac liczby ujemne z tego?

    czy musze losować osobno znak?

    narazie skombinowałem cos takiego :

    int funkcja3(void)
    {
        int i,j,k ,h; 
        cout<<"Podaj ilosc probek do wylosowania:\n";
        cin>>i;
        
        cout<<"Podaj dolny przedział możliwy do wylosowania:\n";
        cin>>j;
        cout<<"Podaj górny przedział możliwy do wylosowania:\n";
        cin>>k;
        
        cout<<"Wylosowane probki:\n";
    
    
    for ( a =0 ; a<i ; a++)
      {
          h=rand()% 1 ;
          cout<<h;
          if(h==1)
          {
                 h=1;
                 }
                 else
                 h=-1;
    z[a]= h * (rand()% 10) ;
    
      cout<<" "<<z[a];
      }
    
    for ( a =0 ; a<p ; a++)
      {
      z[a]=0;  
      }
    
    a = 0;
    
  • #16 6077848
    Raffal_1988
    Poziom 10  
    Posty: 10
    oglonie przyjalem chyba troche inna metode poniewarz nie do konca rozumiem twoje zalozenie natomiast splodzilem cos takego ale nie wiem czy dziala dobrze ; czy da sie znalesc takie kombinacje ze zostana przekroczone progi

    
    int funkcja3(void)
    {
        int i,j,k ,h,h1,h2; 
        cout<<"Podaj ilosc probek do wylosowania:\n";
        cin>>i;
        cout<<"Podaj dolny przedział możliwy do wylosowania:\n-";
        cin>>j;
        cout<<"Podaj gorny przedział możliwy do wylosowania:\n";
        cin>>k;
        cout<<"Wylosowane probki:\n";
    
    for ( a =0 ; a<i ; a++)
      {
          h1=rand() % j ;
          h2=rand() % k ;
          x[a]=h2-h1;
          cout<<h1<<" "<<h2<<" ";
          cout<<x[a];
          h1=0;
          h2=0;
          cout<<"\n";    
    }
    
  • #17 6077991
    Dr.Vee
    VIP Zasłużony dla elektroda
    Posty: 1784
    Pomógł: 307
    Ocena: 76
    Kolego, zamiast pisać takie łamańce, lepiej chwilkę pomyśl.

    Funkcja rand() zwraca liczbę z zakresu [a1, b1). Ty potrzebujesz mieć liczbę z zakresu [a2, b2). Jak chwilę pogłówkujesz, to znajdziesz sposób przekształcenia (przeskalowania + przesunięcia) jednego zakresu w drugi. Pomyśl sobie, że granice zakresu są dwoma punktami wyznaczającymi odcinek - oba punkty musisz przekształcić w taki sam sposób, żeby dostać inny odcinek.

    Później takie samo przekształcenie stosujesz dla liczb zwracanych przez rand() i oto proszę - dostajesz liczby losowe z wybranego zakresu z takim samym (jednostajnym) rozkładem.

    Pozdrawiam,
    Dr.Vee
  • #18 6078247
    Raffal_1988
    Poziom 10  
    Posty: 10
    a mam jeszcze takie pytanie co prawda nie zwiazane z tematem ale jest krotkie :)

    Da sie w programie jakaś funkcja spowodować otwarcie innego programu?

    mam program ktory zapisuje wyliczenia do pliku i chcialbym a zeby ten program wykorzystywal program kolegi ktory rysuje te dane na wykresie a do tego potrzebuje funkcje ktora otworzy ten inny program istnieje taka funkcja?
  • #19 6078379
    Dr.Vee
    VIP Zasłużony dla elektroda
    Posty: 1784
    Pomógł: 307
    Ocena: 76
    Poczytaj o funkcji system().

    Pozdrawiam,
    Dr.Vee

Podsumowanie tematu

✨ Problem powtarzających się liczb losowych generowanych przez funkcję rand() w C++ wynika z ustawiania tego samego ziarna (seeda) na początku programu, zwykle za pomocą srand(time(NULL)), gdzie time() zwraca czas z dokładnością do jednej sekundy. W efekcie przy wielokrotnym uruchomieniu programu w krótkim odstępie czasu generowany jest identyczny ciąg liczb pseudolosowych. Aby uniknąć tego efektu, należy wywołać srand() z unikalnym seedem, np. opartym na czasie lub innych źródłach losowości. Funkcja rand() generuje liczby pseudolosowe na podstawie ziarna i aktualizuje je w cyklu, co powoduje powtarzalność ciągu dla tego samego ziarna. W dyskusji podano przykładowy kod inicjalizacji srand() z time(NULL) oraz generowania liczb z określonego zakresu, w tym z zakresami ujemnymi, poprzez odpowiednie przeskalowanie i przesunięcie wartości zwracanych przez rand(). Zwrócono uwagę, że nie jest konieczne losowanie osobno znaku, a wystarczy matematyczne przekształcenie zakresu. Poruszono także kwestię generowania wielu liczb w krótkim czasie i możliwości wykorzystania bardziej precyzyjnych źródeł czasu lub dodatkowych zmiennych do zwiększenia losowości. Dodatkowo wspomniano o funkcji system() do uruchamiania innych programów z poziomu aplikacji C++.
Wygenerowane przez model językowy.
REKLAMA