Titan91 Δημοσ. 10 Νοεμβρίου 2011 Δημοσ. 10 Νοεμβρίου 2011 Καλησπέρα, Αντιμετωπίζω ένα πρόβλημα με την συνάρτηση random(int num) της C++. Γνωρίζω την βασική της λειτουργία, αλλά κάθε φορά που την καλώ βγάζει τους ίδιους αριθμούς. Για παράδειγμα, έχω ένα μονοδιάστατο πίνακα a[10], τον οποίο θέλω να γεμίσω με τυχαίους αριθμούς από το 0 μέχρι το 10, κάθε φορά που τρέχω το πρόγραμμα. Αν χρησιμοποιήσω την random(10) μέσα σ' ένα βρόγχο, ναι μεν τον γεμίζει κανονικά με τυχαίους αριθμούς αλλά κάθε φορά που τρέχω το πρόγραμμμα εμφανίζει ακριβώς τους ίδιους.
migf1 Δημοσ. 10 Νοεμβρίου 2011 Δημοσ. 10 Νοεμβρίου 2011 Μήπως εννοείς τη συνάρτηση: rand() ; Αν ναι, πρέπει πρώτα να καλέσεις (μια φορά) την srand() η οποία αρχικοποιεί τη γεννήτρια ψευδοτυχαίων. Η πιο δημοφιλής αρχικοποίηση είναι με την τρέχουσα ώρα του συστήματος: > srand( time(0) ); ... int x = rand();
darksize_ Δημοσ. 10 Νοεμβρίου 2011 Δημοσ. 10 Νοεμβρίου 2011 τι γεννήτρια παραγωγής τυχαίων αριθμών χρησιμοποιείς; για random συνάρτηση δε γνωρίζω πάντως μπορείς να χρησιμοποιήσεις την rand() αρχικά μέσω της srand θέτεις ως γεννήτρια παραγωγής τυχαίων αριθμών την ώρα του συστήματος και μετά με την rand κάθε φορά που θα τρέχεις το πρόγραμμα θα παράγονται διαφορετικοί αριθμοί πχ > #include <iostream> #include <ctime> int main(void){ srand(time(NULL)); int foo = rand()%10; std::cout<<foo<<std::endl; std::cin.get(); return 0; } edit: με πρόλαβε ο migf1
Titan91 Δημοσ. 10 Νοεμβρίου 2011 Μέλος Δημοσ. 10 Νοεμβρίου 2011 Ευχαριστώ παιδιά, έτσι δούλεψε > int a[10]; srand( time(0) ); for(int i=0;i<10;i++) { a[i]= 1+random(9); cout<<a[i]<<endl; } Ουσιαστικά τα στοιχεία του πίνακα θα έχουν τιμές από 1 εώς 9
Titan91 Δημοσ. 10 Νοεμβρίου 2011 Μέλος Δημοσ. 10 Νοεμβρίου 2011 Ναι στον builder της borland που χρησιμοποιώ μου δουλεύει μια χαρά.
migf1 Δημοσ. 10 Νοεμβρίου 2011 Δημοσ. 10 Νοεμβρίου 2011 Μάλλον θα είναι non-portable extension. Με στάνταρ C/C++ αυτό που θες να κάνεις γίνεται ως εξής: > ... srand( time(0) ); ... a[i] = 1 + rand() % 9; ...
Titan91 Δημοσ. 10 Νοεμβρίου 2011 Μέλος Δημοσ. 10 Νοεμβρίου 2011 Όντως δεν δουλεύει στο dev c++, στο manual του builder την είδα.
migf1 Δημοσ. 10 Νοεμβρίου 2011 Δημοσ. 10 Νοεμβρίου 2011 Και δεν τη φτιάχνεις μόνος σου... > #include <ctime> int random( int lim ) { srand( time(0) ); return rand() % lim; } int main( void ) { ... a[ i ] = 1 + random(9); ... } Κάνει και re-initialize τη γεννήτρια, οπότε δεν χρειάζεται να την κάνεις εσύ έξω από τη συνάρτηση
παπι Δημοσ. 10 Νοεμβρίου 2011 Δημοσ. 10 Νοεμβρίου 2011 Εφοσον μιλαμε για c++ και ζουμε στο 2011 δες το tr1
nplatis Δημοσ. 11 Νοεμβρίου 2011 Δημοσ. 11 Νοεμβρίου 2011 Αξίζει να πούμε ότι το γεγονός ότι η rand() βγάζει τα ίδια αποτελέσματα κάθε φορά δεν είναι λάθος. Η rand() παράγει ψευδοτυχαίους αριθμούς, δηλαδή αριθμούς που δεν παρουσιάζουν κάποια κανονικότητα ως ακολουθία και έτσι μοιάζουν να είναι τυχαίοι. Όμως δεν πρόκειται για τίποτα άλλο από μια συγκεκριμένη ακολουθία αριθμών (ασφαλώς όχι αποθηκευμένων αλλά που παράγονται αλγοριθμικά). Αυτό που κάνει η srand() είναι να λέει στην rand() από ποιο σημείο της ακολουθίας να ξεκινήσει να δίνει αριθμούς. Όταν βέβαια καλείται με όρισμα την τρέχουσα ώρα, κάθε φορά που τρέχει το πρόγραμμα η ακολουθία θα ξεκινάει από διαφορετικό σημείο. Το ότι οι αριθμοί μοιάζουν να είναι τυχαίοι αλλά είναι πάντα οι ίδιοι (με ίδιο όρισμα στην srand()) μας δίνει τη δυνατότητα να δοκιμάσουμε το πρόγραμμα. Σκεφτείτε ότι φτιάχνετε ένα πρόγραμμα που χειρίζεται τυχαίους αριθμούς, αλλά έχει ένα σφάλμα. Αν η είσοδος των τυχαίων αριθμών που προκαλεί το σφάλμα μπορεί να επαναληφθεί, τότε υπάρχει κάποια ελπίδα να μπορέσουμε να παρακολουθήσουμε το πρόγραμμα ώστε να βρούμε το σφάλμα! Αν δεν μπορούσαμε να λάβουμε την ίδια είσοδο γιατί οι αριθμοί θα ήταν πραγματικά τυχαίοι κάθε φορά, θα ήταν πιο δύσκολο να συναντήσουμε πάλι το σφάλμα. Με βάση τα παραπάνω, καλύτερο θα ήταν η υλοποίηση της random(int) που προτείνεται παραπάνω να μην περιέχει την κλήση στην srand() ώστε να συμπεριφέρεται όσο το δυνατόν πιο κοντά στην απλή rand() -- και μετά αν κάποιος θέλει καλεί την srand() αν και όταν θέλει.
migf1 Δημοσ. 11 Νοεμβρίου 2011 Δημοσ. 11 Νοεμβρίου 2011 ... Με βάση τα παραπάνω, καλύτερο θα ήταν η υλοποίηση της random(int) που προτείνεται παραπάνω να μην περιέχει την κλήση στην srand() ώστε να συμπεριφέρεται όσο το δυνατόν πιο κοντά στην απλή rand() -- και μετά αν κάποιος θέλει καλεί την srand() αν και όταν θέλει. Έτσι όπως τα λες φίλε nplatis είναι (για αυτό και στα αρχικά μας post γράψαμε για ψευδοτυαίους), με μια μικρή επιφύλαξη για το αν πρέπει ή όχι να γίνεται re-seed η γεννήτρια μέσα στην random(). Αν γίνεται μέσα στη συνάρτηση κάθε φορά που καλείται, τότε κάνει το πρόγραμμα λίγο πιο ασφαλές, υπό την έννοια πως δυσκολεύει λίγο περισσότερο τον κακόβουλο να βρει τον ακριβή αριθμό που παράγει κάθε φορά η συνάρτηση. Υπό αυτή την έννοια λοιπόν ίσως είναι καλύτερα να γίνεται re-seed η γεννήτρια μέσα στην random(), και όταν χρειάζεται debugging να χρησιμοποιείται η απλή rand()... ενδεχομένως με χρήση κάποιου pre-processor directive... > int random( int lim ) { #if !DEBUG srand( time(0) ); #endif return rand() % lim; } Βέβαια γενικότερα, ασφάλεια & srand() είναι... αντιφατικές έννοιες
nplatis Δημοσ. 11 Νοεμβρίου 2011 Δημοσ. 11 Νοεμβρίου 2011 Τα πάντα είναι ζήτημα του τι θέλει να κάνει κανείς. Πάντως η φιλοσοφία της C είναι η συνάρτηση να κάνει ένα απλό πράγμα, ενώ αν μπει μέσα και η srand() κάνει δύο πράγματα. Επίσης αν κάποιος γνωρίζει την rand() τότε θα περιμένει και η όποια random(int) να μην καλεί από μόνη της την srand(). Γενικά νομίζω ότι σε μια βιβλιοθήκη δεν θα έβαζες ποτέ random(int) που να περιέχει την κλήση της srand().
migf1 Δημοσ. 11 Νοεμβρίου 2011 Δημοσ. 11 Νοεμβρίου 2011 Σε μια βιβλιοθήκη θα μπορούσες να βάλεις μια 2η παράμετρο, bool, π.χ... > int random( int lim, bool reseed ); EDIT 1: και να παρέχεις κι ένα σχετικό constant directive, π.χ. > #define RND_RESEED 1 ώστε όταν καλείς τη συνάρτηση αντί να περνάς δυσνόητα true ή false να γράφεις π.χ... > ... random( 100, !RND_RESEED ); /* αντί για random( 100, false ); */ ... random( 2000, RND_RESEED ); /* αντί για: random( 2000, true ); */ ... EDIT 2: Και για να είμαστε πλήρως portable (να μη βασιζόμαστε δηλαδή στην implementation dependent διαχείριση του 1 ως true, το directive σε C++ θα πρέπει να το κάνουμε... > #define RND_RESEED true
Προτεινόμενες αναρτήσεις
Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε
Πρέπει να είστε μέλος για να αφήσετε σχόλιο
Δημιουργία λογαριασμού
Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!
Δημιουργία νέου λογαριασμούΣύνδεση
Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.
Συνδεθείτε τώρα