tags:

views:

594

answers:

7

I am trying to generate a good random seed for a psudo-random number generator. I thought I'd get the expert's opinions. let me know if this is a bad way of doing it or if there are much better ways.

#include <iostream>
#include <cstdlib>
#include <fstream>
#include <ctime>

unsigned int good_seed()
{
    unsigned int random_seed, random_seed_a, random_seed_b; 
    std::ifstream file ("/dev/random", std::ios::binary);
    if (file.is_open())
    {
        char * memblock;
        int size = sizeof(int);
        memblock = new char [size];
        file.read (memblock, size);
        file.close();
        random_seed_a = int(memblock);
        delete[] memblock;
    }// end if
    else
    {
        random_seed_a = 0;
    }
    random_seed_b = std::time(0);
    random_seed = random_seed_a xor random_seed_b;
    return random_seed;
} // end good_seed()
A: 

Define good. :-)

Is it important to find a seed quickly, or that the seed be as random as possible no matter how long it takes to put together?

For a balance - definitely not the most random, definitely not the fastest...

  • When it's first called, take the system time, in milliseconds.
  • Run that through a hash function, like SHA-1.
  • Use the result as the seed.

That should give you a mostly-random 160 bits, which is 10^50th or so of variability. The hash will take a split second to run, so this isn't lightning fast, but has been a good balance in the past for me.

Dean J
I'd like to have as random as possible for my application, but I'd be interested in a fast solution too.
posop
@DeanJ The hash is superfluous. Just seed with the system time directly. What you're trying to accomplish with the hash is what (a good) pseudo random number generator already *does* (better).
Jon-Eric
Jon-Eric is 100% correct; on the other hand, I'm used to working with bad random number generators, couldn't tell a good one from a bad one, and tend to stick with (quick) overkill.
Dean J
+1  A: 

Traditionally, we've used first or second user input to seed our values as the (tics to millisecond range) amount of time it takes them to respond is pretty variable.

Michael Dorgan
+4  A: 

The code that reads from /dev/random seems wrong: you're C-style casting the address of your character buffer into random_seed_a (plug for C++ casts here) and ignoring anything you actually read from /dev/random (try *reinterpret_cast<int*>(memblock).

/dev/random should already be a good entropy source, so if it's available don't possibly taint the value with any other data and just use it as the seed directly. If there isn't enough data in /dev/random I would just fall back on the time and use that by itself rather than xor'ing it with something.

Mark B
according to my studies a non-deterministic random variable "dev/urandom" xor-ed with a not so random variable time(0) will still be a non-deterministic random variable.
posop
+2  A: 

Good pseudo-random number generators don't need a "good" seed, any seed (that's different from run to run) works equally well.

Using system time directly is fine (and common). Using /dev/random is also fine.

If your pseudo-random number generator isn't good, even picking a "good" seed won't help. Replace it if you can.

Suggestions: Mersenne twister is a pretty well regarded. Here's a precursor which will run on even the most limited of systems.

Jon-Eric
Depending on the purpose, a pseudo-random number generator may need an unpredictable seed. There was an on-line poker game that fed the time into what may have been a decent PRNG, which meant that it was possible, by observing some cards, to figure out where the PRNG started, and hence to know the whole deck.
David Thornley
If it's *at all* important for users to not be able to predict the random number sequence, then you want a cryptographically secure generator, not a pseudorandom generator. (You're crazy if you base real-money gambling on a pseudorandom generator.)
Jon-Eric
Just FYI, with Mersenne twister, you have to observe 624 consecutive cards (12 decks) before you know all the future cards.
Jon-Eric
@Jon-Eric: True. To give the poker site due credit, they weren't gambling their own money, although I suspect they lost business once word got around.
David Thornley
A: 

Maybe you should prefer /dev/urandom/ over /dev/random. The latter blocks on Linux if there is not enough entropy available, which can easily happen if the program runs on a machine without user interaction. In case you cannot open /dev/urandom, you could throw an exception instead of using a fallback.

Philipp
+1  A: 

"Good" generators, "Bad generators" it doesn't mean anything. "Anyone who considers arithmetical methods of producing random digits is, of course, in a state of sin." - John von Neumann. Every such generator is just a deterministic algorithm. It's very important to have initial states ( seed ) that bring enough entropy. Depending on what you need, you should test your generator quality. Monte Carlo method is a very good estimator of a pseudo random number generator.

bartek
+1  A: 

Ok here's the changes I made after considering your input. Thanks for everything by the way!

unsigned int good_seed()
{
    unsigned int random_seed, random_seed_a, random_seed_b; 
    std::ifstream file ("/dev/urandom", std::ios::binary);
    if (file.is_open())
    {
        char * memblock;
        int size = sizeof(int);
        memblock = new char [size];
        file.read (memblock, size);
        file.close();
        random_seed_a = *reinterpret_cast<int*>(memblock);
        delete[] memblock;
    }// end if
    else
    {
        random_seed_a = 0;
    }
    random_seed_b = std::time(0);
    random_seed = random_seed_a xor random_seed_b;
    std::cout << "random_seed_a = " << random_seed_a << std::endl;
    std::cout << "random_seed_b = " << random_seed_b << std::endl;
    std::cout << " random_seed =  " << random_seed << std::endl;
    return random_seed;
} // end good_seed()
posop