I was toying around with arrays, populating with pseudo random numbers, finding minimum and maximum values and their indices and number of occurrences and I noticed something strange - when using srand seeded with time the number of minimum and maximum value occurrences is ALWAYS equal. This doesn't seem very random to me.
Is there an alternative way of getting a DIFFERENT number of minimum and maximum value occurrences, as one would expect with random numbers?
Here is my code (I am learning so it may be messy and inefficient, recommendations are welcome)
#include <cstdlib>
#include <iostream>
#include <time.h>
using namespace std;
void findExtremes( const int[], int);
int main()
{
const int lenght = 2000; //define lenght
int array1[lenght];
srand(time(0));
for ( int i = 0; i < lenght; i++) //populate array with random numbers and print them out
{
array1[i] = rand() % 3000;
cout << "Index " << i << " = " << array1[i] << endl;
}
findExtremes(array1, lenght); // call fn
return 0;
}
void findExtremes( const int array[], int size)
{
int maxV, minV, maxI, minI;
maxV = array[0];
minV = array[0];
minI = 0;
maxI = 0;
for ( int i = 1; i < size; i++)
{
if ( array[i] > maxV)
{
maxV = array[i];
maxI = i;
}
if ( array[i] < minV)
{
minV = array[i];
minI = i;
}
}
//find the number of occurances for min and max values
int minOcc = 0;
int maxOcc = 0;
for ( int i = 1; i < size; i++)
{
if (array[i] == minV)
minOcc++;
if (array[i] == minV)
maxOcc++;
}
//output
cout << "\nMinmim value is index " << minI << " with value " << minV << " and " << minOcc << " occurances" << endl;
cout << "\nMaxium value is index " << maxI << " with value " << maxV << " and " << maxOcc << " occurances" << endl << "\n";
}
For a start, they're actually pseudo random numbers, not random numbers. In any case, it may be that a a truly random sequence has that exact property that you're seeing :-) The sequence 1,1,1,1,1 is as equally likely to occur in a truly random set as much as 5,2,4,2,99.
If you want a "more random" random sequence, I wouldn't be using the normal ones shipped with C libraries (unless those libraries were written by people who understand randomness) - you should look into things like the Mersenne Twister, using /dev/random (if under Linux) and so on.
You may also want to look at this snippet of your code.
if (array[i] == minV)
minOcc++;
if (array[i] == minV)
maxOcc++;
I believe that last if should be comparing with maxV rather than minV. Otherwise there is zero chance that your minimum and maximum counts will be different.
When I make that change (and change % 3000 to % 30, to get a range of duplicates), I see:
Minmim value is index 112 with value 0 and 65 occurances
Maxium value is index 24 with value 29 and 58 occurances
And, not that it really matters in terms of this question, you may want to clean up your spelling somewhat:
lenght -> length.
minmum -> minimum
maxium -> maximum
occurances -> occurrences
I perform numerical simulations on Physics and my group uses the GSL library for that:
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
class Random
{
private:
gsl_rng* r; //!< Pointer to the gsl rng
public:
//! Constructor: uses argument as the seed
Random(long unsigned int seed);
long int R(int N);
long double R();
long double gaussianR(long double sigma);
};
inline Random::Random(long unsigned int s)
{
r = gsl_rng_alloc( gsl_rng_taus );
gsl_rng_set(r, s); //seed to use to the pseudo-aleatory number generator.
}
// a uniform number between 0 and N-1
inline long int Random::R(int N)
{
return gsl_rng_uniform_int (r, N);
}
// a uniform number between 0 and 1
inline long double Random::R()
{
return gsl_rng_uniform_pos( r );
}
// a gaussian distribution with sigma
inline long double Random::gaussianR(long double sigma)
{
return gsl_ran_gaussian(r, sigma);
}
you have to compile it with flags:
OTHER_LDFLAGS = -lgsl -lm -lgslcblas
and add includes and libs (this is for fink installation case):
HEADER_SEARCH_PATHS = /sw/include
LIBRARY_SEARCH_PATHS = /sw/lib
Hope this helps.
You can use the new random library included in C++11, or you can use the Boost::Random library that it was based off.
The behaviour of your Pseudo-Random Number Generator (PRNG) is perfectly normal.
In fact, if your draw enough numbers from rand(), you will always get the same extrema, since it is uniformly distributed.
In your case, the question is: do you need another behaviour? You should not pounce on True Random Numbers as #sehe suggests. This might be useless, and even problematic when dealing with stochastic simulations, which Monte Carlo algorithms are. Imagine that you want to debug a code snippet based upon random numbers, or that of colleague of yours intends to check your results: how would you do if you were not able to reproduce the same random sequence?
That is one of the reason why PRNGs are sufficient and often preferred when you do not need crypto-secure random numbers.
I think the problem is that your initial statement is wrong. The code is provides different numbers each time. I tried you unmodified code and there are the results:
Minmim value is index 1194 with value 0 and 1 occurances
Maxium value is index 1264 with value 2995 and 1 occurances
Minmim value is index 1958 with value 1 and 1 occurances
Maxium value is index 1510 with value 2991 and 1 occurances
...
However, there are two bugs in the code:
In the second for loop, you should start with i = 0.
You should compare with maxV instead of minV in the same loop.
With regards to the random number generation:
When seeded with the same number, a series of rand() calles should return the same numbers. rand() is not for random numbers, but for pseudo-random numbers. rand() should be have this way because than e.g. a simulation will output the same results when started with the same seed. It is a very nice property.
You seed it with the current time, which is ok and therefore rand() should return a different series of numbers each time (at least when not called multiple times a second). The seeding looks good to me. It is in fact very similar to the example provided here.
The sample size is 2000 and the range of generated numbers is 3000. This means that it is not probable that the minimal size and the maximal size are always the same. If the sample size would be a million, with a high probability 2999 should be the largest number in the very most runs.
Gentlepeople: NOTE
Yes! This answer is "old". And in the era of c++11, by all means use c++11 <random>. But please don't downvote this question, years after the fact because you think "Ew Everybody knows rand() is evil!". In fact, it is not. It's just limited, and very easy to use inappropriately. But - as an historic fact, it exists as an API and it is still useful to document how you can use it better. I'm not deleting this answer for very reason.
Original answer:
Please read
http://eternallyconfuzzled.com/arts/jsw_art_rand.aspx
Notably, don't write rand() % 3000. Write
int r = rand() / ( RAND_MAX / 3000 + 1 );
In fact, random should be uniformly distributed, meaning that indeed the lower and upper bound would have near 100% chance of occurring when the number of samples is large enough (larger than the size of the domain, for starters).
That's what true random is about (try to do a Monte-Carlo algorithm without it - you'd be very unhappy)
Related
I have a rand number generator.
Now my question is how do I get for instance the first/second/third/fourth digit of the generated random number.
Implementing this so the user can use a hint when guessing the number.
example: result(rand): 9876
print hint 1: second number 8
print hint 2: fourth number 6
Whats the best way to tackle this? I've been thinking to convert the string to an char array in order to print out the certain locations where the values are being kept but that won't work I guess.
Correct me if my way of asking this questions is very bold.
int nummer = 4;
std :: string result = "";
for (int i = 0; i < nummer; i++)
{
result.push_back(rand()%10 + '0');
}
You have two options for solving this problem:
Create one random number between 0 and 9999 and then calculate the individual digits.
Create four random numbers between 0 and 9 which represent the individual digits and then, if necessary, calculate the whole number from the individual digits.
Normally, doing option #1 would be more straightforward. You seem to be going for option #2. Both ways are possible and which one is better probably depends on whether your program works more with the number as a whole or with individual digits.
If you decide to do option #2, then the question arises whether you want to work with ASCII character codes between '0' and '9' (i.e. codes between 48 and 57) or with actual numbers between 0 and 9. Normally, it is a bit easier to work with the actual numbers instead of ASCII character codes, but both ways are feasible.
Personally, I would solve it the following way:
#include <iostream>
#include <cstdlib>
#include <ctime>
int main()
{
//seed random number generator
std::srand( std::time(nullptr) );
//note that NUM_DIGITS should not be set so high
//that MAX_NUMBER is not representable as an `int`
constexpr int NUM_DIGITS = 4;
//set this to the highest possible number that
//corresponds to NUM_DIGITS
constexpr int MAX_NUMBER = 9999;
//this variable holds the entire number
int random;
//this array holds the individual digits
int digits[NUM_DIGITS];
///generate the random number
random = std::rand()%(MAX_NUMBER+1);
//calculate the individual digits of the random number
int remaining = random;
int divisor = (MAX_NUMBER+1) / 10;
for ( int i = 0; i < NUM_DIGITS; i++ )
{
digits[i] = remaining / divisor;
remaining = remaining % divisor;
divisor/= 10;
}
//print the whole random number
std::cout << "Whole random number:\n" << random << "\n\n";
//print the individual digits
std::cout << "Individual digits:\n";
for ( int i = 0; i < NUM_DIGITS; i++ )
{
std::cout << digits[i] << "\n";
}
}
Sample output (actual output depends on random number seed):
Whole random number:
8695
Individual digits:
8
6
9
5
I've been thinking to convert the string to an char array but that won't work I guess.
I see no reason to do this. In your posted code, you can simply write
result[0]
result[1]
result[2]
result[3]
to access the individual digits of the number.
In that respect, converting a std::string to a C-style character array has no advantages.
The code you've written is fine.
Whether you store the characters in an array or a string, you can access the elements using result[i] where i starts at 0.
I've been thinking to convert the string to an char array but that won't work I guess.
Using std::string is usually a better idea - still possible but a little harder to screw them up, and they're more powerful generally, but you could use a char array if you wanted:
char result[] = "0000"; // will have null terminator
for (int i = 0; i < 4; ++i)
result[i] = rand() % 10 + '0';
Letting result be a 5-character array - with a null terminator - means you can still print all four digits easily with std::cout << result.
Alternatively, you could pick a random 4-digit number and convert it to a string of a particular width, using '0's to pad:
#include <iostream>
#include <iomanip>
int main() {
std::ostringstream oss;
oss << std::setw(4) << std::setfill('0') << rand() % 10000;
std::cout << '[' << oss.str() << "]\n";
}
I made this program for generating prime numbers. I know there are lots of formulas for generating them 100x faster, but this is what I did.
I tried to divide i with all numbers under i. That was the simplest method, but I though it was inefficient, since after dividing by 2 you don't need to divide by 4 and so on.
I made a list of prime numbers smaller than i, and divided i by that list's numbers. I went through the list using std::iterator, because I saw it being used in all stackoverflow answers and other tutorials. It turned out to be a lot slower. Like it took 22 seconds instead of 2.
I tried to use an int to go through the list, and it took 2 seconds again.
Next, I used 1 000 000 to see the difference between method 1 and 3. To my amazement method 1 was faster. Why is that? Shouldn't using only prime numbers to test be faster than using all numbers?
#include <iostream>
#include <vector>
#include <chrono>
int main()
{
std::cout << "how high do you want to generate prime numbers? ";
int x;
// typed 1 000 000
std::cin >> x;
auto starttime = std::chrono::high_resolution_clock::now();
std::vector<unsigned int> primes;
bool isPrime;
for (int i = 2; i <= x; ++i) {
isPrime = true;
// takes 293 seconds
//for (int div{ 2 }; div < i; ++div) {
// if ((i % div) == 0) {
// takes really really long
//for (std::vector<unsigned int>::iterator div = primes.begin(); div != primes.end(); ++div) {
//if ((i % *div) == 0) {
// takes 356 seconds
for (int iter = 0; iter < primes.size(); ++iter) {
if ((i % primes[iter]) == 0) {
isPrime = false;
break;
}
}
if (isPrime) {
primes.push_back(i);
std::cout << i << " ";
}
}
std::cout << "generating prime numbers up to " << x << " took " <<
round(static_cast<std::chrono::duration<double>>((std::chrono::high_resolution_clock::now() - starttime)).count())
<< " seconds.";
}
its because of usage vector<unsinged int> for third method.
especially primes.push_back which leads to allocations. Try to primes.reserve initially
I'd say the main issue is that most frequently a number is divisible by 2 and thus it isn't prime. I suppose the first method is more friendly with compiler and cache. But it is hard to tell for sure. Also, try to remove printing and test for time spent. Printing tends to slow the code a lot depending on usage.
A standart method for determining all prime numbers (there are more efficient ones but this one is fairly simple).
Create vector A of boolean that will indicate whether the number is prime or not. But at start set all variables to true - except A[0]=A[1]=false.
Run for loop from i = 2 to x. If A[i] is false then skip it - i is not prime. If A[i] is true then i is prime and set all A[i*k] to false for all 1<k<x/i.
This should be more efficient either of the methods.
I have generated 100 random numbers, where I have to shorted out equal even and odd numbers of the random numbers. All even or odd numbers can not be repetitive.
For example I will create 100 random numbers
#include <iostream>
#include <cstdlib>
int main()
{
for (int i=1; i <=100; ++i){
//double p = rand();
std::cout <<"random number is :" << rand()<<std::endl;
}
}
Since I don't know if the even and odd numbers are same in the list from the 100 random numbers, I want to pick minimum number of pair even and odd numbers. I also will like to know what the total odd and even numbers are generated separately. One note is that, if for an example, any even or odd number get printed out multiple times, I want to consider that as a one.
For example. Let's assume we have 60 even and 40 odd numbers from the printed random numbers. And also from the 60 even numbers 10 even numbers are repetitive. So I would consider the different event numbers are 50. The printed out numbers would be first 20 even numbers and first 20 odd numbers.
The reason I want to do this is because I want to learn How I can filter out the even and odd numbers from the for loop of random generator.
UPDATE:
My goal is to find even and odd numbers from the generated random numbers. When I short out the even and odd numbers, all the even and odd numbers will be different. Which means, if I found even number 2 printed out 5 times, I would still consider that one. In this way I want to find the minimum number of even and odd numbers.
Lets have an example:
the generated print out is: {1,2,2,3,4,5,6,8,9,3,2,4,6,10}
From the list the even and odd numbers would be:
even = {2,4,6,8}
odd = {1,3,5,9}
If you looked carefully, I excluded 10 from the even shorting. The reason is that, If i added 10 in the even list, I would have more even than odd.
Use std::unorderd_set to create odd set and even set
to check number is odd = (num&1) will be 1 for odd and 0 for even
std::unordered_set<int> set_odd;
std::unordered_set<int> set_even;
for (int num : nums) {
if (num & 1) set_odd.insert(num);
else set_even.insert(even);
}
This will do what you explained in your example.
#include <set>
#include <vector>
int main()
{
std::vector<int> numbers = {1, 2, 2, 3, 4, 5, 6, 8, 9, 3, 2, 4, 6, 10};
std::set<int> even, odd;
// sort the numbers into even and odd sets
for (auto const& n : numbers)
{
if (n % 2 == 0)
even.insert(n);
else
odd.insert(n);
}
// figure out which set is smaller
int min = std::min(even.size(), odd.size());
// print out the evens
std::cout << "even = ";
auto it = even.begin();
for(int i = 0; i < min; ++i)
{
std::cout << *(it++) << " ";
}
std::cout << std::endl;
// print out the odds
std::cout << "odd = ";
it = odd.begin();
for(int i = 0; i < min; ++i)
{
std::cout << *(it++) << " ";
}
std::cout << std::endl;
}
If you only want pairs of random numbers (pair as in collection of 2-integers, one even, one odd, not std::pair), you need a way to generate the numbers, provide storage for the pairs, and keep track of the number of odds generated and number of evens generated and a way to associate the pairs of numbers generated.
To generate the random numbers std::random_device provides random number generation for int from your choice of random number engines such as the std::mersenne_twister_engine. You can generate a number within a std::uniform_int_distribution simply by declaring the device, seeding the generator with the device and then creating a distribution between a min and max of your choice.
To setup and generate random numbers within the positive range of int you could do:
...
#include <random>
#define NMAX std::numeric_limits<int>::max()
...
std::random_device rd; /* delcare the randon number generator device */
std::mt19937 gen(rd()); /* standard mrsene_twister engine seeded w/rd */
std::uniform_int_distribution<int> dist(0, NMAX); /* create disribution */
And to request a number from the distribution, simply:
int r = dist(rd); /* generate rand */
How to store the pairs generated depends on how you coordinate adding the even and odd numbers generated to coordinate storing pairs of numbers together. You can use a std::map or std::unordered_map or simply use an even and odd std::vector<int>. Using the latter allows you to fill an vector of evens and a vector of odds and then simply output the lesser .size() of the two to capture the pairs of even-odd generated out of our 100 random integers.
For example:
#define MAXRAND 100
...
std::vector<int> even, odd;
...
for (int i = 0; i < MAXRAND; i++) { /* loop MAXRAND times */
int r = dist(rd); /* generate rand */
if (r % 2 == 0) /* if even */
even.push_back(r); /* add to even vector */
else /* odd number */
odd.push_back(r); /* add to odd vector */
}
That way you can specify to generate 100 random numbers and you end up with however many even-odd pairs were generated out of those 100 random numbers -- which sounds like what you were asking.
Putting it altogether you could do:
#include <iostream>
#include <iomanip>
#include <random>
#include <vector>
#define NMAX std::numeric_limits<int>::max()
#define MAXRAND 100
int main (void) {
std::vector<int> even, odd;
std::random_device rd; /* delcare the randon number generator device */
std::mt19937 gen(rd()); /* standard mrsene_twister engine seeded w/rd */
std::uniform_int_distribution<int> dist(0, NMAX); /* create disribution */
size_t limit = 0;
for (int i = 0; i < MAXRAND; i++) { /* loop MAXRAND times */
int r = dist(rd); /* generate rand */
if (r % 2 == 0) /* if even */
even.push_back(r); /* add to even vector */
else /* odd number */
odd.push_back(r); /* add to odd vector */
}
/* output results */
limit = (even.size() > odd.size()) ? odd.size() : even.size();
std::cout << limit << " even-odd pairs (0 - " << NMAX << ")\n\n";
for (size_t p = 0; p < limit; p++)
std::cout << std::setw(12) << even.at(p) <<
" " << odd.at(p) << '\n';
}
Example Use/Output
Running you will generally generate between 40-50 pairs of numbers -- the random distributions being fairly good, e.g.
$ ./bin/evenoddpairs
48 even-odd pairs (0 - 2147483647)
1513290664 712950177
2014370968 990873219
161619218 6719997
2062410942 1965300831
2072442520 938385103
669324326 1957687455
1201350414 2134189381
217290372 1304388089
726760634 232069103
2086887656 1784024967
1345123406 185879429
1706842790 686104759
1034648158 268926351
1445724500 1996600823
1303450734 1890287253
763120758 1581912187
1788401668 1537971261
1542967608 1842999149
377964104 1995119937
87264498 644262155
224210492 519040373
692262016 372293591
502458404 1867793795
575578512 751306553
373162704 170423471
1502626218 152785903
284546326 287967359
388031960 1233214425
1839930048 243652639
465469190 1747259241
1488469408 252779515
2144753340 1992139979
2010564888 298805387
917820234 187798339
1204892922 1454685783
563347322 50283749
1303887182 345841727
1429521892 1668482773
702286146 1191166889
1490493310 963750729
986716484 1522036479
1107465502 1445768043
1613852374 1307939505
1584334086 1565159437
1325156802 354726127
1165679412 1618569419
1192475084 1341169211
71913214 1569003463
There are many ways to put this together, but given your constraint of generating 100 random numbers and then collecting only the even-odd pairs created out of those 100 numbers, the even/odd vectors is a simple to ensure you ended up with only the pairs generated out of the 100. Let me know if that is what you were asking or if you were asking something slightly different.
If you need to enforce only unique random numbers, you can fill an std::unordered_map from your two vectors.
I have the following:
std::random_device rd;
std::mt19937_64 randEng(rd());
std::uniform_real_distribution<double> rg(std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max());
for(size_t i = 0; i < numToGenerate; i++){
nums[i] = rg(randEng);
std::cout << nums[i] << std::endl;
}
Where nums is a vector presized to numToGenerate
Every number that is printed out though says inf my understanding was that I had set this up to get random numbers between in this case -1.79769e+308 and 1.79769e+308 as it happens to be on my machine. What am I doing wrong here in the set up of this random number generator
Probably the computation of the pseudorandom number includes the difference (max-min). For example to compute a random number between A and B a simple approach would be:
x = A + rnd*(B - A)
where rnd is a random number between 0 and 1. If you do this with the maximum and minimum double precision value you get a problem, because that difference is bigger than the maximum and thus will become "infinite".
After that A + rnd*infinite is always infinite if rnd is not zero, and NaN when it's zero.
here x,y<=10^12 and y-x<=10^6
i have looped from left to right and checked each number for a prime..this method is very slow when x and y are somewhat like 10^11 and 10^12..any faster approach?
i hv stored all primes till 10^6..can i use them to find primes between huge values like 10^10-10^12?
for(i=x;i<=y;i++)
{
num=i;
if(check(num))
{
res++;
}
}
my check function
int check(long long int num)
{
long long int i;
if(num<=1)
return 0;
if(num==2)
return 1;
if(num%2==0)
return 0;
long long int sRoot = sqrt(num*1.0);
for(i=3; i<=sRoot; i+=2)
{
if(num%i==0)
return 0;
}
return 1;
}
Use a segmented sieve of Eratosthenes.
That is, use a bit set to store the numbers between x and y, represented by x as an offset and a bit set for [0,y-x). Then sieve (eliminate multiples) for all the primes less or equal to the square root of y. Those numbers that remain in the set are prime.
With y at most 1012 you have to sieve with primes up to at most 106, which will take less than a second in a proper implementation.
This resource goes through a number of prime search algorithms in increasing complexity/efficiency. Here's the description of the best, that is PG7.8 (you'll have to translate back to C++, it shouldn't be too hard)
This algorithm efficiently selects potential primes by eliminating multiples of previously identified primes from consideration and
minimizes the number of tests which must be performed to verify the
primacy of each potential prime. While the efficiency of selecting
potential primes allows the program to sift through a greater range of
numbers per second the longer the program is run, the number of tests
which need to be performed on each potential prime does continue to
rise, (but rises at a slower rate compared to other algorithms).
Together, these processes bring greater efficiency to generating prime
numbers, making the generation of even 10 digit verified primes
possible within a reasonable amount of time on a PC.
Further skip sets can be developed to eliminate the selection of potential primes which can be factored by each prime that has already
been identified. Although this process is more complex, it can be
generalized and made somewhat elegant. At the same time, we can
continue to eliminate from the set of test primes each of the primes
which the skip sets eliminate multiples of, minimizing the number of
tests which must be performed on each potential prime.
You can use the Sieve of Eratosthenes algorithm. This page has some links to implementations in various languages: https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes.
Here is my implementation of Sieve of Erathostenes:
#include <string>
#include <iostream>
using namespace std;
const int k = 110000; //you can change this constant to whatever maximum int you would need to calculate
long int p[k]; //here we would store Sieve of Erathostenes from 2 to k
long int j;
void init_prime() //in here we set our array
{
for (int i = 2; i <= k; i++)
{
if (p[i] == 0)
{
j = i;
while (j <= k)
{
p[j] = i;
j = j + i;
}
}
}
/*for (int i = 2; i <= k; i++)
cout << p[i] << endl;*/ //if you uncomment this you can see the output of initialization...
}
string prime(int first, int last) //this is example of how you can use initialized array
{
string result = "";
for (int i = first; i <= last; i++)
{
if (p[i] == i)
result = result + to_str(i) + "";
}
return result;
}
int main() //I done this code some time ago for one contest, when first input was number of cases and then actual input came in so nocases means "number of cases"...
{
int nocases, first, last;
init_prime();
cin >> nocases;
for (int i = 1; i <= nocases; i++)
{
cin >> first >> last;
cout << prime(first, last);
}
return 0;
}
You can use the Sieve of Erathostenes to calculate factorial too. This is actually the fastest interpretation of the Sieve I could manage to create that day (it can calculate the Sieve of this range in less than a second)