random number question

Started by
20 comments, last by DevFred 15 years, 9 months ago
Quote:Original post by nightech
Quote:Original post by Sync Views
3.044e-005 <--ok...so why are there results over 1?

3.044e-005 is scientific notation for 0.00003044 ;) so it's not generating over 1 at all, just closer to 0.

Look at what the numbers represent. About 10% of the generated numbers are between 0 and 0.1, another 10% between 0.1 and 0.2 and so forth. What the OP didn't understand why there was "more than no" number betwenen 1.0 and 1.1 (it's because 1 is between 1.0 and 1.1).
Advertisement
Yep :). Now what i'm wondering is how come it's faster than the standard rand() that I assumed was optimised?
How much faster than two additions, one multiplication and one division can you get? I presume rand() is tied by some ancient specification regarding its output values, but I really dunno.
Quote:
Now what i'm wondering is how come it's faster than the standard rand() that I assumed was optimised?


The pseudo random number generator in MSVC is awful. Never really heard of anyone who actually uses it. I don't think it's even truly uniform and it has a really bad period length. The recommendation of using boost::random is really the best recommendation. In there they have several versions of the Mersenne Twister which is very fast, uniform and has a really good period length. It's really good for Monte Carlo simulations but doesn't work at all for cryptography though, not that the MSVC one is any better. There are faster implementations than the boost Mersenne Twister version but I doubt that's where your bottleneck will be.
Quote:Original post by DevFred
I would actually love to write
        div = (std::numberic_limits<unsigned>::max() + 1) / bound;        return operator()() / div;
but of course a number one greater than the maximum is very unlikely to exist

Then perhaps you need to investigate Schrage's algorithm.

You also need to make sure you choose your constants correctly and that the seed value of your sequence is adjusted to avoid pathalogical conditions. Writing a simple PRNG is not as easy as it appears.

The Boost PRNGs are similar to the TR1 PRNGs and will do exactly what you need. They're entirely in header files so no extra linkifications. They're very well tested and verified by experts in the field.

The tr1 PRNGs (at least) also provide streamable states so you can save and restore the state of the PRNG, or even exchange it over the wire to synch between, say, client and server. For multiplayer thyat could be a bonus.

Stephen M. Webb
Professional Free Software Developer

Quote:Original post by Bregma
Writing a simple PRNG is not as easy as it appears.

That's why I started my first reply with the following words:
Quote:Original post by Bregma
the last resort is to write your own Pseudo Random Number Generator class
I still don';t really get the boost thing though...

class mt : public Random{	boost::mt19937 mt((unsigned)time(NULL));	public:	virtual double Uniform()	{		static boost::variate_generator			<boost::mt19937& ,boost::uniform_real<>> 			rng(mt,boost::uniform_real<>(0,1));//Is this 0 <= x < 1? The docs don't seem to say...		return rng();	}	virtual double Uniform(double Min, double Max(	{		//Isn't there a way to avoide creating all this for EVERY number?		//but then wouldn't multipliying the above be pretty bad having already mapped it to 0...1?		boost::variate_generator			<boost::mt19937& ,boost::uniform_real<>>			rng(mt,boost::uniform_real<>(Min, Max);		return rng();	}};
Quote:Original post by Sync Views
Isn't there a way to avoide creating all this for EVERY number?

Sure, just construct the necessary objects ONCE and then create random numbers. After reading the docs for 5 minutes, this is a small example I copy-and-pasted together with minor mods, works great:
#include <iostream>#include <boost/random.hpp>int main(){    boost::mt19937 generator(42u);    boost::uniform_real<> uni_dist(0, 1);    boost::variate_generator<boost::mt19937&, boost::uniform_real<> > uni(generator, uni_dist);    for (int i = 0; i < 100; ++i)        std::cout << uni() << std::endl;}

It looks like you're still creating or own class... why do you do this? Just use the existing boost classes.
THe point I'm making is how do I change the range...rather than then remapping the 0-1 to whatever I want at that particular time (eg 50-100)
If you use boost, you'd use a uniform_real distribution that you supply the arguments 50 and 100. See DevFred's post for other details.

This topic is closed to new replies.

Advertisement