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.:)
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;
}No huhhuh! Opettajalla ei sitten selvästikään ole pätevyyttä :)
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.
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;
}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.
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.
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.
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 - 9Aihe on jo aika vanha, joten et voi enää vastata siihen.