Mulla on siis nyt vaikkapa funktiot N() ja K(), joista N() arpoo numeron välillä 0-9 ja lähettää sen numeron samaan tapaan kuin Visual Basicissa SendKeys, ja K() tekee muuten saman, mutta kirjaimilla. Ongelma on siinä, että
N(); K(); N(); K(); N(); K();
tuottaa jotain tämäntapaista: 6N6N6N. Toi kyllä toimii jos jokaisen väliin noista laittaa jonkun jumalattoman pitkän Sleepin() mutta siinä kestääää.
Et kertonut mitään arvontatavastasi, mutta kristallipallo sanoo, että kutsut srand-funktiota joka välissä, vaikka sitä kuuluu kutsua vain kerran aluksi.
Jees, ja sama ongelma on kaiksisa Delphin, C:n, C++:n ja Pascalin versioissa, ja funktion lähdekoodi on huippusalainen?
Vaikka kristallipalloni onkin pölyssä, niin veikkaan että funktiosi käyttää aikaan satunnaismoottorin siemenlukuna kellonaikaa tms. ja nopeiden kutsujen välillä aika ei ehdi muuttua, joten satunnaisuus alustetaan aina samalla siemenluvulla.
Voisit kokeilla alustaa satunnaisgeneraattorin vain ohjelman alussa etkä ollenkaan itse funktioissa.
(Edit: Metabolix näköjään jo arvaili samaa)
Jos siemenluku on kellonaika sekunteina, saman sekunnin aikana arvotut luvut ovat aina samat.
Sama ilmiö näkyy Windowsin pasianssissa, jos painat F2-napin (uusi peli) pohjaan.
Joo on huippusalainen ;) Mutta kiitos, hyvin teillä kristallipallot toimii :) Pitää vielä vähän parannella tota..
Jos haluat kokeilla vaihtoehtoista random-funktio toteutusta, niin alla on OpenWatcom C-kutsuttava random-funktio (toimiva, testattu), sekä todennäköisesti toimiva käännös Delphille (sori, en osaa pascalia. Mahdollisten virheiden korjaus jätetään harjoitukseksi).
Delphi-versio olettaa, että siemenluku muuttujat seed1: integer ja seed2: integer on määritelty jonnekin ohjelmaan globaaleiksi.
Molemmat funktiot tietysti vaativat, että siemenluku muuttujat asetetaan kerran ohjelmassa, ennenkuin funktiota kutsutaan ensimmäisen kerran. Arvot voi ottaa vaikka kellonajasta.
OpenWatcom C-kutsuttava:
.386p _DATA SEGMENT DWORD PUBLIC USE32 'DATA' public _random_var1 public _random_var2 _random_var1 dd 3 ; siemenluku1 _random_var2 dd 5 ; siemenluku2 _DATA ENDS DGROUP GROUP _DATA _TEXT SEGMENT PARA PUBLIC USE32 'CODE' ASSUME CS:_TEXT, DS:_DATA public Random1_ Random1_ proc near push ebx push edx cmp eax, 0 jz @random_exit cmp eax, 0xFFFFFFFF jz @random_exit mov ebx, eax mov eax, 0x4019CF16 mul _random_var1 add eax, _random_var1[4] mov _random_var1, eax adc edx, 0 mov _random_var1[4], edx xor edx, edx inc ebx div ebx xchg edx, eax @random_exit: pop edx pop ebx ret Random1_ endp _TEXT ends end
Delphi asm-funktio:
function Random1(range : integer): integer;assembler asm push ecx push edx cmp eax, 0 jz @random_exit cmp eax, 0xFFFFFFFF jz @random_exit mov ecx, eax mov eax, 0x4019CF16 mul seed1 add eax, seed2 mov seed1, eax adc edx, 0 mov seed2, edx xor edx, edx inc ecx div ecx xchg edx, eax @random_exit: pop edx pop ecx end;
Taas kerran, Boost tarjoaa toimivan ratkaisun.
http://www.boost.org/doc/libs/1_39_0/libs/
Pieni esimerkki:
boost::mt19937 r; // Mersenne-twister generaattori. boost::uniform_int<> d(1, 10); // Arvotaan numeroita 1-10 väliltä; distribuutio. boost::variate_generator<boost::mt19937&, boost::uniform_int<> > arpa(r, d); int luku = arpa();
Jaahas, jälkimmäisten herrojen kristallipallot sanovatkin siis aloittajan ongelman olleen se, että tämän satunnaislukugeneraattori on liian yksinkertainen ja helppokäyttöinen. Vaikea laji tuo ennustaminen... :)
itse kyhään satunnaiset lukuni niin, että jos haluan for -silmukassa esimerkiksi sarpoa useita lukuja, teen sen jotakuinkin näin:
for( int i = 0; i < 10; i++ ){ srand( time(0) + i); //jne.. }
tällöin takaantuu se, että tulos on joka kerralla eri.
Edit:: tai se mitöön takaa, takaapa vain sen että siemenluku on joka kerralla eri
tosin tunnustan että ihan varmuuden varaksi(lue: omaksi iloskeni) teen niistä lausekkeista monimutkaisempia tyyliin:
srand (apu2*time(0) + apu1*i);
saman toki voi tehdä ilmankin silmukoita, mutta silloin apumuuttujaa kuitenkin pitäisi kasvattaa aina välissä
Ja minkäköhän ihmeen takia sinä noin teet? Satunnaislukujen laatu ei automaattisesti parane vaihtamalla siemenlukua mahdollisimman usein, varsinkaan jos tämän uuden siemenluvun satunnaisuus on huono, kuten tuossa koodissasi, jossa tuo srand
in kutsuminen käytännössä vain huonontaa lopputulosta.
Jos haluat laadukkaampia satunnaislukuja, vaihda satunnaislukugeneraattoria. Tämä onnistuu esimerkiksi goalan näyttämällä tavalla. Myös siemenluvun satunnaisuutta voi tarvittaessa parantaa, mutta noin se ei kyllä onnistu.
EDIT: Jos et usko, niin kokeile, mitä seuraava ohjelma tulostaa:
#include <stdio.h> #include <stdlib.h> #include <time.h> void tulosta_satunnaisluvut( int n ) { for( int i = 0; i < n; i++ ) { srand( time(0) + i); printf("%d ", rand() % 10); } printf("\n"); } int main() { tulosta_satunnaisluvut( 5 ); tulosta_satunnaisluvut( 6 ); tulosta_satunnaisluvut( 7 ); return 0; }
Satunnaisuus on vaikea laji, eikä deterministisellä koneella ole mahdollista saavuttaa aitoa satunnaisuutta, koska tulos on näillä jokaisella kaavalla tarkasti etukäteen tiedossa. Lisäksi kannattaa miettiä tuottaako siemenluvun muutos oikeasti satunnaisuutta tuloksiin, kuten os edellä jo mainitsikin.
Saattaa nimittäin käydä niinkin, että generaattorin tuottama satunnisuus häviää tuolla tavalla olemattomiin. Hassun hauskassa c++ oppaassa on artikkeli aiheesta, johon kannattaa tutustua ennen omia sävellyksiä. Putkassa on ennenkin keskusteltu omista satunnaisluvuista.
Teuro kirjoitti:
Satunnaisuus on vaikea laji, eikä deterministisellä koneella ole mahdollista saavuttaa aitoa satunnaisuutta, koska tulos on näillä jokaisella kaavalla tarkasti etukäteen tiedossa. Lisäksi kannattaa miettiä tuottaako siemenluvun muutos oikeasti satunnaisuutta tuloksiin, kuten os edellä jo mainitsikin.
No tuo nyt meni jo aika pitkälti offtopiciksi alkuperäisen kysyjän kannalta. Mutta jos tarvitsee aitoa satunnaisuutta, niin ainahan voi hankkia jonkin tällaisen ja onhan esimerkiksi Linuxissa kohtuullisen hyvä satunnaisuuslähde ilman erillistä rautaakin, kun se kerää satunnaisuutta altaaseen erilaisista koneen jossain määrin satunnaisista tapahtumista.
no okei, myöönän virheeni - tässä tapauksessa - koska tässä ilmiselvästi virhe on. joskus kuitenkin onnistuin siemenlukua muuttamalla ehkäisemään saman luvun jatkuvan toistumisen sekuntin aikana, ja se oli mielestäni riittävä keino, vaikka kumpikaan noista edellisessä viestissäni mainituista "kaavoista" nyt ei toimikkaan aivan niinkuin oli tarkoitus
ByteMan kirjoitti:
no okei, myöönän virheeni - tässä tapauksessa - koska tässä ilmiselvästi virhe on. joskus kuitenkin onnistuin siemenlukua muuttamalla ehkäisemään saman luvun jatkuvan toistumisen sekuntin aikana, ja se oli mielestäni riittävä keino, vaikka kumpikaan noista edellisessä viestissäni mainituista "kaavoista" nyt ei toimikkaan aivan niinkuin oli tarkoitus
Välttäisit sen muutenkin, jos alustaisit satunnaislukugeneraattorisi vain kerran (kuten on tarkoitus). (Käsittääkseni) useimmat C:n standardikirjaston satunnaislukugeneraattorien toteutukset muodostavat näennäisen satunnaisen lukunsa aina edellisen luvun perusteella (tai ensimmäisen luvun tapauksessa siemenluvun avulla) yksinkertaisen kerto-yhteenlasku-jakojäännös-laskun avulla, eikä laskun tuloksen pitäisi olla n millään luvulla n (ts. jäädä "jumiin").
@eq: ....öööh just :D oli pakko tarkistaa toi nii niihä se sit näköjään toimiiki
sillon ku sain käsityksen että se luku vaihtuu vain sekuntin välein olin ilmeisesti vahingossa laittanut srand( time(0) ); -rivin for silmukkaan sisälle...
ja koska ohjelma aina kääntyi ilman virheitä en vaivautunut ikänä menemään referencestä tarkistamaan toimiiko se oikeasti niin -.-
Aihe on jo aika vanha, joten et voi enää vastata siihen.