Προς το περιεχόμενο

Τυχαίοι αριθμοί σε C++


Giorgos3924

Προτεινόμενες αναρτήσεις

Δημοσ.

Καλησπέρα!

Πώς μπορούμε να φτιάξουμε μια συνάρτηση που θα βγάζει τυχαίους αριθμούς

από ένα συγκεκριμένο εύρος τιμών;

πχ η συνάρτηση θα βγάζει έναν τυχαίο αριθμό (περισσότερους μέσα σε βρόγχο for) που θα επιλέγει από το εύρος που δηλώνουμε με ορίσματα.

Κάτι τέτοιο γίνεται με τη random() στη C αλλά βγάζει αριθμό από μεγάλο εύρος.

Η συνάρτηση που ψάχνω θα ήταν κάπως έτσι:

rand_numb(x,y)

Και θα έβγαζε έναν αριθμό από το x έως το y

Μετά θέλω να την βάλω σε βρόγχο for ώστε να επιλέγω το πλήθος των τυχαίων.

Και μια λεπτομέρεια: Θα ήθελα κάθε αριθμός να είναι μοναδικός, έτσι ώστε από το διάστημα 5-20 αν ήθελα να πάρω 3 αριθμούς να μην εμφάνιζε πάνω από μια φορά τον ίδιο.

Μπορεί να γίνει μια τέτοια συνάρτηση;

Για τους όμοιους αριθμούς μπορεί να βρεθεί και λύση μέσα στη for οπότε οποιος μπορεί ας βοηθήσει στη συνάρτηση λίγο.

Ευχαριστώ!

Δημοσ.

Καταρχήν όσον αφορά την συνάρτηση, μπορείς να βασισθείς στην «rand() % μαξ-τιμή-1» η οποία επιστρέφει τιμές από το μηδέν ως την «μαξ-τιμή-1», για να λάβεις και την μαξ-τιμή στο αποτέλεσμα απλά την αυξάνουμε κατά μια μονάδα (πχ. rand() % «μαξ-τιμη + 1»). Αυτό θα λύσει το πρόβλημα εύρους μέγιστων τιμών, όμως το πρόβλημα μίνιμουμ τιμών παραμένει. Για να λυθεί αυτό αρκεί ένας βρόγχος ο οποίος θα ελέγχει αν η τιμή είναι μικρότερη της μίνιμουμ αποδεκτής. Για παράδειγμα:

 

>int _Random(const int& From, const int& To)
{
   // Return a random number from range "From" - "To" ..
int Number;

do
{
	Number = rand() % (To + 1);
}while(Number < From);

return Number;
}

 

Για να έχεις πραγματικά ψευδοτυχαίους αριθμούς πριν καλέσεις την rand() φρόντισε να προετοιμάσεις την γεννήτρια ψευδο-τυχαίων αριθμών της C/C++ με την εντολή srand(time(NULL)); η οποία ορίζει το seed της γεννήτριας με βάση την τιμή του real-time clock του υπολογιστή σου.

 

Όσον αφορά την καταχώρηση μοναδικών τυχαίων αριθμών μπορεί να γίνει με διάφορους τρόπους, ο πιο εύκολος είναι η καταχώρηση των αριθμών σε κάποιο STL container (πχ. vector NumberList) αφού μιλάμε για C++, οπότε όταν παράγεις κάποιον νέον αριθμό αναζητείς την καταχώρηση του στον container αυτό (πχ. μέσο find) και αν υπάρχει παράγεις κάποιον άλλο, διαφορετικά τον καταχωρείς επαναλαμβάνοντας τα βήματα αυτά μέχρι να παράγεις τον απαιτούμενο αριθμό μοναδικών τυχαίων τιμών (προσοχή μόνο να ζητάς εύρος τιμών που μπορεί να παράγει τον απαιτούμενο αριθμό μοναδικών αριθμών).

 

Ακολουθεί ένα παράδειγμα γραμμένο σε C++ Builder, το οποίο εκτυπώνει 3 μοναδικούς αριθμούς (μεταξύ 5 ως 20) στην οθόνη:

 

>
// Random Numbers! Dx.
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <vector>
#include <ctime.h>

using namespace std;

int _Random(const int& From, const int& To);

int main(void)
{
vector<int> NumberList;

// Init. RNG with RTC seed.
srand(time(NULL));
// Generate ten random but not repeatable numbers.
for(int Count = 0; Count < 3; Count++)
{
	// Random number variable.
	static int RndNum;
	// Generate a unique random number
	while(1)
	{
		// Random number values from 5 to 20
		RndNum = _Random(5, 20);
		// Is number unique?
		if(find(NumberList.begin(), NumberList.end(), RndNum) ==
			NumberList.end())
		{
			// Yes, store it in NumberList for future reference..
			NumberList.push_back(RndNum);
			// Generate next random number..
			break;
		}
	}
	// Echo to stdout..
	cout << setfill('0') << setw(2) << RndNum << endl;
}

// End of program.
return 0;
}

int _Random(const int& From, const int& To)
{
   // Return a random number from range "From" - "To" ..
int Number;

do
{
	Number = rand() % (To + 1);
}while(Number < From);

return Number;
}

 

Το πρόγραμμα φυσικά μπορεί να περιέχει Bugs ή άλλες αβλεψίες.

 

Καλή συνέχεια!!

Δημοσ.

Και η δικια μου εκδοχη

>class Random
{
private:
std::vector<int> m_catch;
int m_from;
int m_to;
int Next()
{
	return m_from +( rand() % (m_to - m_from));
}
bool Exist(int i)
{
	auto it = m_catch.begin();
	while(it != m_catch.end())
	{
		if(*it == i)
			return true;
	    ++it;
	}
	return false;
}
public:
Random()
{
	m_from = 0;
	m_to   = 0;
}
Random(int from,int to)
{
	m_from = from;
	m_to   = to;
}
int NextRandom()
{

	if((m_to - m_from) <= m_catch.size())
		return -1;
	int ret;
	while(this->Exist((ret = this->Next())));
	m_catch.push_back(ret);
	return ret;
}

};
int main(void) 
{
Random r(100,103);

cout<<r.NextRandom()<<endl;
cout<<r.NextRandom()<<endl;
cout<<r.NextRandom()<<endl;
cout<<r.NextRandom()<<endl;
cout<<r.NextRandom()<<endl;
cout<<r.NextRandom()<<endl;
return 0;
}

Δημοσ.
Πραγματικά τυχαιοι αριθμοι απο οσο ξερω για να γινουν χρειάζεται ειδικο hardware!

Αλλα αυτο ειναι υπερεξεζητημένο..

 

Μη το λες, και χωρις hardware μπορεις να εχεις πραγματικο τυχαιο αριθμο. Υπαρχουν καποιες μεταβλητες που ειναι random πχ, time, stack pointer, heap pointer,cpu temp, hdd temp mem temp, ip etc..

Δημοσ.

@Giorgos3924

 

Πέραν των παραπάνω απαντήσεων να έχεις υπόψην σου τα εξής :

 

To θέμα των τυχαίων αριθμών είναι πολύ σημαντικό σε ορισμένους κλάδους (π.χ. προσoμοιώσεις monte carlo που έχουν εκαταμύρια ή δισεκατομύρια τυχαίες τιμές)

και έχουν καταβληθεί μεγάλες προσπάθειες για να φτιαχτούν αξιόπιστες γεννήτριες τυχαίων αριθμών.

Καμιά από τις ενσωματωμένες εντολές δεν παράγει πραγματικά τυχαίους αριθμούς διότι βασίζεται σε κάποια συγκεκριμένη σχέση (συνήθως εμπλέκεται το υπόλοιπο της

διαίρεσης και η αποκοπή ψηφίων). Αυτό που επιδιώκεται είναι η στατιστική τυχαιότητα (ψευδοτυχαίοι αριθμοί).

Γίνεται προσπάθεια η ακολουθία που παράγουν τέτοιες σχέσεις να έχει την μέγιστη δυνατή περίοδο, άρα οι αριθμοί να έχουν χαμηλή επαναληψιμότητα.

 

Δίνοντας διαφορετική αρχική τιμή (seed) σε ρουτίνες τύπου rand() αλλάζει και η παραγόμενη ακολουθία αφού η συνάρτηση που την παράγει έχει κάθε φορά διαφορετικό όρισμα (η ώρα αλλάζει συνέχεια).

Ωστόσο το να τίθεται ίδιο seed (όπερ σημαίνει ότι παράγονται οι ίδιοι αριθμοι) είναι χρήσιμο σε περιπτώσεις debugging.

 

Μηχανήματα που παράγουν πραγματικά τυχαίους αριθμούς χρησιμοποιούν ειδικά κόλπα όπως τον θερμικό θόρυβο των αντιστάσων (που έιναι στ' αλήθεια τυχαίος).

 

Το % επιστρέφει το υπόλοιπο της ακέραιας διαίρεσης. Ωστόσο για αρνητικούς αριθμούς μπορεί να έχεις εκπλήξεις....

Δημοσ.
Μη το λες, και χωρις hardware μπορεις να εχεις πραγματικο τυχαιο αριθμο. Υπαρχουν καποιες μεταβλητες που ειναι random πχ, time, stack pointer, heap pointer,cpu temp, hdd temp mem temp, ip etc..

 

 

 

γιαυτο μονο το καλοκαιρι τα items στο L2 δεν σπανε ευκολα :devil:

 

 

 

 

joke , joke :P

 

 

Δημοσ.

Αυτό θα λύσει το πρόβλημα εύρους μέγιστων τιμών, όμως το πρόβλημα μίνιμουμ τιμών παραμένει. Για να λυθεί αυτό αρκεί ένας βρόγχος ο οποίος θα ελέγχει αν η τιμή είναι μικρότερη της μίνιμουμ αποδεκτής. Για παράδειγμα:

 

>int _Random(const int& From, const int& To)
do
{
	Number = rand() % (To + 1);
}while(Number < From);

 

Έτσι χάνεις και στην ποιότητα των παραγόμενων αριθμών και στην απόδοση

του προγράμματος λόγω ότι θα απορρίπτει τιμές. Η έκδοση του Ευγένιου

"m_from +( rand() % (m_to - m_from)" είναι πιο δόκιμη. Αν θέλεις τιμές από το 10

έως το 30, βρίσκεις τυχαίες τιμές από το 0 μέχρι το 20 και τις προσθέτεις στο 10.

 

Σύμφωνα με αυτό:

iSecret = rand() % 10 + 1;

Βγάζει τους ίδιους αριθμούς, με την ίδια σειρά δηλαδή.

 

Καταρχήν όσον αφορά την συνάρτηση, μπορείς να βασισθείς στην «rand() % μαξ-τιμή-1» η οποία επιστρέφει τιμές από το μηδέν ως την «μαξ-τιμή-1», για να λάβεις και την μαξ-τιμή στο αποτέλεσμα απλά την αυξάνουμε κατά μια μονάδα (πχ. rand() % «μαξ-τιμη + 1»).

 

Ο "αλγόριθμος" αυτός χρησιμοποιείται σχεδόν παντού αλλά δεν είναι και τόσο

καλός γιατί παίρνει το υπόλοιπο της διαίρεσης, οπότε ένα σημαντικό μέρος

του αριθμού δεν λαμβάνεται υπόψην.

 

>
iSecret = μαξ-τιμή * rand() / (RAND_MAX + 1.0);

 

Ο παραπάνω αλγόριθμος θα δώσει καλύτερα αποτελέσματα. Το αναφέρω μήπως

χρησιμεύσει σε κάποια περίπτωση. Σε ένα απλό πρόγραμμα, δεν μας καίει

και τόσο πόσο τυχαίος θα είναι ο αριθμός, οπότε και ο κλασικός αλγόριθμος

δουλεύει μια χαρά.

Δημοσ.
Έτσι χάνεις και στην ποιότητα των παραγόμενων αριθμών και στην απόδοση

του προγράμματος λόγω ότι θα απορρίπτει τιμές. Η έκδοση του Ευγένιου

"m_from +( rand() % (m_to - m_from)" είναι πιο δόκιμη. Αν θέλεις τιμές από το 10

έως το 30, βρίσκεις τυχαίες τιμές από το 0 μέχρι το 20 και τις προσθέτεις στο 10.

Συμφωνώ, αν και θα αύξανα κατά + 1 το “to” του “Random(int from,int to)” function ώστε να επιστρέφει και την μάξιμουμ τιμή στο αποτέλεσμα.

Αρχειοθετημένο

Αυτό το θέμα έχει αρχειοθετηθεί και είναι κλειστό για περαιτέρω απαντήσεις.

  • Δημιουργία νέου...