Avatar billede ducks Nybegynder
22. september 2004 - 09:24 Der er 19 kommentarer og
2 løsninger

Random numre i C++

Hvordan laver man random numre i C++?
Jeg har prøvet at kigge på http://www.roberjacobs.fsnet.co.uk/random.htm men kan ikke lige gennemskue det

Og hvad med en C++ reference, hvor finder jeg en ordentlig en af den slags?
Avatar billede Slettet bruger
22. september 2004 - 09:32 #1
jeg syntes at Cplusplus.com er udmærket :) prøve at søge der
Avatar billede thomas_nj Nybegynder
22. september 2004 - 13:52 #2
Er det noget lignede detteher du søger? http://cplus.about.com/library/weekly/aa041303c.htm
Avatar billede arne_v Ekspert
22. september 2004 - 17:11 #3
Tilfældige tal (mere præcist: pseudo random numbers) er et område, hvor der
findes en stor teori og masser af kode.

Der er indbygget 2 funktioner i ANSI C (altså standard og derfor finde i alle
C og C++ compilere): srand og rand.

Simpelt eksempel:

#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

int main()
{
  srand(time(NULL));
  for(int i=0;i<10;i++)
  {
      double r = 0.01*(rand()%100);
      cout << r << endl;
  }
  return 0;
}
Avatar billede arne_v Ekspert
22. september 2004 - 17:12 #4
En simpel algoritme med kode:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

static unsigned long int seed;

void mysrand(unsigned long int ss)
{
  seed=ss;
  return;
}

unsigned long int myrand()
{
  seed=(16807*seed) % 2147483647;
  return seed;
}

int main(int argc,char *argv[])
{
  int i;
  mysrand(time(NULL));
  for(i=0;i<10;i++) {
      printf("%ld\n",myrand());
  }
  exit(0);
}
Avatar billede arne_v Ekspert
22. september 2004 - 17:13 #5
En noget mere avanceret med kode:

#include <stdio.h>
#include <stdlib.h>

static unsigned long int seed[5];

void mysrand(unsigned long int ss[])
{
  seed[0]=ss[0];
  seed[1]=ss[1];
  seed[2]=ss[2];
  seed[3]=ss[3];
  seed[4]=ss[4];
  return;
}

unsigned long int myrand()
{
  unsigned long int res;
  int i;
  res=(107374182*seed[0]+104480*seed[4])%2147483647;
  seed[4]=seed[3];
  seed[3]=seed[2];
  seed[2]=seed[1];
  seed[1]=seed[0];
  seed[0]=res;
  return res;
}

int main(int argc,char *argv[])
{
  unsigned long int ss[5];
  int i;
  ss[0]=1234567;
  ss[1]=123;
  ss[2]=4444;
  ss[3]=987;
  ss[4]=12321;
  mysrand(ss);
  for(i=0;i<10;i++) {
      printf("%ld\n",myrand());
  }
  exit(0);
}
Avatar billede arne_v Ekspert
22. september 2004 - 17:13 #6
Skriv hvis du vil vide mere om algoritmerne og deres egenskaber.
Avatar billede arne_v Ekspert
22. september 2004 - 17:14 #7
Til simple ting er den indbyggede standard god nok.

Til mere avancerede ting kan der være behov for bedre algoritmer.
Avatar billede ducks Nybegynder
24. september 2004 - 01:24 #8
Hvornår bruger man mere avancerede?
Avatar billede arne_v Ekspert
24. september 2004 - 07:26 #9
Simple algoritmer vil typisk gentage sig selv efter f.eks. 2 milliarder tal.

Hvis man f.eks. skal lave en simulation hvor man skal bruge 1 billio tal, så
er det næppe smart at gentage 2 milliarder tal i præcis samme rækkefølge
500 gange.

Nogle af de dårlige algoritmer har meget lidt tilfældighed i de laveste bits.
Hvis du vil bruge rand()%2 så check for guds skyld om algoritmen returnerer
skiftevis lige og ulige tal (fordi så vil rand()%2 skiftevis returnere 0 og 1).
Avatar billede blackautt Nybegynder
24. september 2004 - 15:09 #10
Hvis du nu skal bruge det til f.eks. et rollespil eller lignende, så bruger jeg tit denne funktion som tager et seed fra klokkeslettet. Den er forholdsvis god og efter min mening, let at bruge.

int diceRoller(int min_value, int max_value)
{
  int random;
  srand ( static_cast <unsigned> (time(0)) );
  while(1)
  {
    random = rand();
    if((random >= min_value)&&(random <= max_value))
      break;     
  }
  return random;
}

Du kalder den så bare, fra der hvor du skal bruge den (hvis du skal bruge store tal, ændrer du naturligvis bare typen af variabel).
Avatar billede arne_v Ekspert
24. september 2004 - 20:56 #11
Det er et glimrende eksempel.

På hvordan man ikke skal gøre det !!!!
Avatar billede arne_v Ekspert
24. september 2004 - 20:56 #12
#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

int diceRoller(int min_value, int max_value)
{
  int random;
  srand ( static_cast <unsigned> (time(0)) );
  while(1)
  {
    random = rand();
    if((random >= min_value)&&(random <= max_value))
      break;   
  }
  return random;
}

int main()
{
  for(int i=0;i<10;i++)
  {
      cout << diceRoller(0,1000) << endl;
  }
  return 0;
}
Avatar billede arne_v Ekspert
24. september 2004 - 20:56 #13
Output fra 2 kørsler:

C:\>bad
675
675
675
675
675
675
675
675
675
675

C:\>bad
594
594
594
594
594
594
594
594
594
594
Avatar billede arne_v Ekspert
24. september 2004 - 20:57 #14
ALDRIG kalde srand mere end en gang.

(og der findes hurtigere metoder til at få en værdi mellem min og max)
Avatar billede arne_v Ekspert
24. september 2004 - 21:20 #15
#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

int diceRoller(int min_value, int max_value)
{
  return (min_value + (int)((rand()/(double)RAND_MAX)*(max_value - min_value)));
}

int main()
{
  srand ( static_cast <unsigned> (time(0)) );
  for(int i=0;i<10;i++)
  {
      cout << diceRoller(0,1000) << endl;
  }
  return 0;
}

må være lidt bedre
Avatar billede blackautt Nybegynder
25. september 2004 - 11:28 #16
Ja, der er andre og bedre metoder, hvis man skal bruge mange tal lige efter hinanden. Mit eksempel fungerer også kun optimalt i et spille miljø, som f.eks. et RPG, hvor mange tal i træk ikke er nødvendigt. :)

Jeg skal lige være sikker på dit eksempel Arne, hvis man putter det ind, er det så nødvendigt at indkapsle hele indholdet af sin main i "srand ( static_cast <unsigned> (time(0)) );  for(int i=0;i<10;i++){program.....}" ?
Avatar billede arne_v Ekspert
25. september 2004 - 11:46 #17
srand skal kaldes en gang først.

for løkken er udelukkende fordi jeg vil generere N tilfældige tal.

Det kan sikker laves pænere og mere OO'sk. Eksemplet var kun for at vise
at med kun et kald til srand så fik man bedre tilfældige tal (og at man kunne
omregne til min..max interval).
Avatar billede arne_v Ekspert
25. september 2004 - 11:47 #18
Selvom der er lang tid mellem kald så er rand algoritmerne baseret på at man
kalder srand en gang og rand mange gange.

Eventuelle gode matematiske egenskaber ved en algoritme gælder ikke
hvis man kalder srand hele tiden.
Avatar billede ducks Nybegynder
02. oktober 2004 - 15:59 #19
Beklager at jeg ikke har svaret tilbage :( Men mit power kabel til min bærbar er gået i stykker, og det er der jeg har mit C++ projekt liggende, skal nok komme tilbage så hurtigt som muligt, når jeg har den igen. Om ca 1 uge.
Avatar billede ducks Nybegynder
13. oktober 2004 - 14:01 #20
arne_v ligger du et svar?
Avatar billede arne_v Ekspert
13. oktober 2004 - 14:03 #21
ok
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester