There is a bug in the implementation of rand() for Visual C++ 10 (probably others) and it does not generate random numbers! There are two problems, the small size of the result (32767 max, hence there should be too many duplications after calling it many times) and it simply does not generate random numbers when tested using Chi-Squared. Supposedly, the lower bits are less random in many implementations -- in this case, the middle bits are less random! Try rand()/100 % 2 and check the results!
Here is the program (and, it does call srand() which is NOT required for generating random numbers, just for providing a "random" seed!
/*
Chi Squared (from
http://c2.com/cgi/wiki?ChiSquared)
A simple statistical test that can be useful for testing the
randomness of a distribution:
Generate a uniform distribution d[0..r] using the (suspected)
PseudoRandomNumberGenerator you want to test and doing N runs.
N should be greater than say 10*r.
The average fill in each slot in d is f = N/r
ChiSquared = Sum[0<=i<r](((d[i]-f)^2)/f)
If ChiSquared is within 2*Squareroot(r) of r 90% of the time,
the generator passed this test.
Note that being within these limits 95% of the time if just as bad
as only being within them 85% of the time. This test is necessary
but not sufficient - it is easy to construct distributions that
pass the test and are obviously not random. (For example, mod r
of each of the numbers from 1 to N.)
-- JanLarsen
*/
#include <iostream>
#include <ctime>
#include <cmath>
using namespace std;
// function prototype
int myRand();
int main() {
const int R = 6; // number of "buckets." 6 simulates a die; 2 a coin flip;
// 12 with sum of two "rolls" for dice [would require
//changing the expected frequency!]; etc.
long long d[R] = {0}; // following the above, d will be the "buckets"
// for counting random values
long long n = 0; // number of trials. Should be bigger than 10 * r.
float f = 0.0; // this will be the computed expected frequency for each
//d[i] and will be (<float> N )/ R
float chiSquared = 0.0;
cout << "Enter the number of trials: ";
cin >> n;
// see if n is big enough
if(n < (10 * R)) {
cout << "The number of trials should be at least" << 10 * R
<< " for statistical validity." << endl;
return -1;
}
f = (float) n /R; // expected frequency value
srand(static_cast<int>(time(0))); // randomize the randomizer.....
for(long long trials = 0; trials < n; trials++) {
d[rand()/100 % R]++; // middle digits are actually worse! Try with myRand() for good results
// supposedly, the low digits of some
// random number generators are not very random!
// Also test with "digits" closer to middle of
// number by dividing rand() by powers of r (or of 10?).
}
// compute the Chi-Squared value for the test.
float diff[R] = {0.0};
for(int i = 0; i < R; i++) {
diff[i] = d[i] - f;
chiSquared += (diff[i] * diff[i]) / f; // or diff ** 2 would work, too!
}
// report results
cout << endl << endl <<
"The actual and expected distributions for each die value" << endl;
cout << "Die Value Difference" << endl;
for(int i = 0; i < R; i++) {
cout << i + 1 << " " << diff[i] << endl;
}
cout << endl;
cout << "Chi-Squared for this distribution is : " << chiSquared << endl;
cout << "This should be between " << (R - (2.0 * sqrt((float) R))) <<
" and " << (R + (2.0 * sqrt((float) R)));
if( chiSquared > (R - (2.0 * sqrt((float) R))) &&
chiSquared < (R + (2.0 * sqrt((float) R))) ) { // test for significance
cout << " and is significant; i.e., passed the test.";
} else {
cout << " and is not significant!!!!";
}
cout << endl;
return 0;
}
// Since rand() is obviously not a very good random number generator for large numbers,
// I looked at
http://en.wikipedia.org/wiki/Linear_congruential_generator
long long randValue = (static_cast<int>(time(0)) & 0X7FFFFFFF) | 0X01;
// insures a 32-bit value that is odd
// 2741 could be an initial seed (which happens to be the 400th prime number)
// this could be initialized with time() * 2 + 1 to generate an
// odd-valued starting point.
int myRand() {
randValue = ((1103515245 * randValue) + 12345) & 0X7FFFFFFF; // glibc values from above
return static_cast<int>(randValue);
}