Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: satunnaislukuja tulostava ohjelma

Sivun loppuun

keijokoodaaja [10.12.2004 09:56:27]

#

Tässä teille koodaajat kunnon pähkinä purtavaksi. Eli tarkoitus olisi tehdä ohjelma joka täyttää taulukon [100] satunnaisluvuilla väliltä [-25, 25], ja tulostaa taulukon sekä kertymäsumman. Eli pähkinä sinäänsä koska opettajakaan ei tätä osannut.:)

sqwiik [10.12.2004 12:33:17]

#

Jos opettaja ei tätä osaa, niin opettaja on *piip*...
Luku välillä [-25,25] saadaan vaikka funktiolla rand() (palauttaa satunnaisen positiivisen kokonaisluvun). Taulukko on sitten toki vaikka signed int (signed char:kin kävisi, jos kaikki luvut ovat välillä [-25,25]). Kun katsot hieman tarkemmin, tuo alue onkin satunnainen luku välillä [0,50] ja josta on vähennetty 25... Eli täyttö menee mekanismilla random(50) - 25. rand()-funktiota käytettäessä katsotaan jakojäännös 51:n kanssa (0...50).
Seuraavassa on taulukon luonti ja täyttö, keksi kertymäsumman lasku itse :)

//inuta header, jossa rand() esitellään. Ja time.h jos
//halutaan enemmän satunnaisuutta.
signed int taulu[100]; //tai signed char. Alustamisella ei
                       //ole väliä, koska se täytetään kuitenkin.
signed int a, luku;
//alustetaan rand(), korvaa 12000 time()-funktiolla jos
//sisällytit time.h:n (enemmän satunnaisuutta)
srand(12000);
for(a = 0; a < 100; a++){
  taulu[a] = rand()%51 - 25;
}

rndprogy [10.12.2004 12:35:53]

#

No huhhuh! Opettajalla ei sitten selvästikään ole pätevyyttä :)

jutti [11.12.2004 00:12:00]

#

Jos ope on nipo, se voi valittaa siitä, että koska RAND_MAX % 51 on noin 26, rand() % 51 tuottaa hieman harvemmin luvut 27:stä ylöspäin. Suhteessa 642/643 suunnilleen. Mitä suurempi jakaja, sitä merkittävämmäksi ongelma kasvaa. Esim. rand() % 22000 tuottaa tuplasti enemmän lukuja 0 - 11000 kuin lukuja 11000 - 22000.

Metabolix [11.12.2004 00:25:36]

#

Ja jotta kukaan ei nipota siitä, muutetaan koodi tällaiseksi:

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

int main()
{
  signed int Taulu[100];
  srand((unsigned int)time(0));
  rand(); // Yksi tyhjä rand(), koska syystä tai toisesta ensimmäinen arvottu luku on aina 0

  for (int A = 0; A < 100; A++)
    Taulu[A] = 51 * rand() / RAND_MAX - 25;

  // Ja tänne nuo kertymäsummat ja muut
  return 0;
}

FooBat [11.12.2004 01:00:32]

#

Integer jakolaskujen kanssa kannattaa sitten olla tarkkana :)

Metabolixinkin kannattaa tarkistaa tuleeko
51 * rand() / RAND_MAX
lausekkeesta joskus jotain muuta kuin nollaa. Mun mielestä se kaipaa double-castia johonkin väliin.

Metabolix [11.12.2004 01:32:57]

#

FooBat kirjoitti:

Metabolixinkin kannattaa tarkistaa - -

Eipä tarvitsekaan :)
51 * rand() = [0 .. 51 * RAND_MAX] = [0 .. 1671117] (VC++:lla ainakin)
[0 * RAND_MAX .. 1 * RAND_MAX - 1] / RAND_MAX = 0
[1 * RAND_MAX .. 2 * RAND_MAX - 1] / RAND_MAX = 1
[2 * RAND_MAX .. 3 * RAND_MAX - 1] / RAND_MAX = 2
jne.
Eli kyllä tämä toimii, kun vain on laskujärjestys oikein. Sen sijaan rand() / RAND_MAX * 51 vaatii double-/float-castin jakolaskuun, koska jakolasku tehdään esnin, ja kokonaisluvuilla siitä on 1/RAND_MAX mahdollisuus saada 1, muuten tulee 0.

FooBat [11.12.2004 01:48:04]

#

Käsittääkseni joissakin ympäristöissä tuo RAND_MAX on hyvin lähellä MAX_INT:iä (vai mikä se nyt onkaan), jolloin käytännössä
51*MAX_INT <= MAX_INT ja
x / MAX_INT = 0, kun x < MAX_INT

En myöskään muista oliko C:ssä laskujärjestys tarkoin määrätty tapahtuvaksi vasemmalta oikealle. Periaatteessahan kerto ja jakolasku ovat saman arvoisia ja jotkut hassut kääntäjät voivat tehdä asian vähän eri lailla.

Metabolix [11.12.2004 02:53:04]

#

Näköjään tosiaan ainakin joissakin UNIX-pohjaisissa. Siinä näyttäisi kattona olevan 0x7fffffff eli 2 ^31 - 1. No, kai sitä pitää vaivautua tekemään porttautuvaa koodia. Tuosta laskujärjestyksestä veikkaisin, että ainakin sulkujen lisääminen varmaankin varmistaa oikean järjestyksen.
Edit: Tässä uusi hieno Random-funktioni (ehdot toimivat ainakin VC++:lla):

int Random(int Range)
{
#if (RAND_MAX == 0x7fff)
	// RAND_MAX = 2^15, joten kahdella saadaan luvut 0 - 2^30.
	// Yhtä käyttäen isoissa arvonnoissa joitakin lukuja ei tulisi koskaan-
	return (int)(Range * ((rand() | (rand() << 15)) / 1073741824.0));
#else
#if (RAND_MAX == 0x7fffffff)
	// jos RAND_MAX on 2^31, se riittää sellaisenaan
	return (int)(Range * (rand() / 2147483648.0));
#else
	// jos RAND_MAX on jotakin muuta, arvotaan suoraan
	return (int)(Range * (rand() / (double)RAND_MAX));
#endif
#endif
}

// Random(10) palauttaa siis luvun 0 - 9

Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta