Generating random numbers effectively

2020-04-24 17:20发布

How do you generate random numbers effectively?
Every time a random number program boots up, it starts spitting same numbers as before. (I guess because of quasi nature of random number generation)
Is there a way, that random# generation becomes non-deterministic? sort of Entropy addition to generation that number generated after boot is in different sequence than last one. (random random rather that quasi-random)
Also, say range of such generation is (m,n) such that n-m = x, is there a chance that a number say 'p' appears next time after x-1 other numbers have been generated. But next lot of such x numbers would not be same as sequence from last one. Example:
range: 1,5. Generation : 2,4,5,1,3 (1st) 4,2,3,1,5 (2nd)... same numbers.
I out of nonplussed state of mind wrote this :

int num1 = (rand.Next(1, 440) *31* (int)DateTime.Now.Ticks *59* (DateTime.Now.Second * 100) % 439) + 1;
int num2 = (rand.Next(1, 440) *31* (int)DateTime.Now.Ticks *59* (DateTime.Now.Second * 100) % 439) + 1;

here range was (1,440). but it still generates numbers out of bound and zero, and it's frequency is not that great either. It is C#.NET code. Why so?
your answers can be language agnostic / algorithmic / analytical. Thanks in advance.

5条回答
Melony?
2楼-- · 2020-04-24 17:37

You can use a chaotic map to generate random numbers. The C++ code below (GenRandRea) returns a vector of random number using the so-called "Tent map" (https://www.wikiwand.com/en/Tent_map). The seed is an integer that is used to generate x (as a number between 0. and 1.) as input of the iterative map. Diferent seeds will generate different sequences.

vector<double> GenRandRea(unsigned seed, int VecDim){
double x, y, f;
vector<double> retval;

x = 0.5*(abs(sin((double)seed)) + abs(cos((double)seed)));

for (int i = 0; i<(tentmap_delay + VecDim); i++) {
    if ((x >= 0.) && (x <= 0.5)) {
        f = 2 * tentmap_r * x;
    }
    else {
        f = 2 * tentmap_r * (1. - x);
    }

    if (i>=tentmap_delay) {
        y = (x*tentmap_const) - (int)(x*tentmap_const);
        retval.push_back(y);
    }
    x = f;
}
return retval;

}

with

const double tentmap_r = 0.75; //parameter for the tent map
const int tentmap_delay = 50; /*number of interactions in the tent map 
                              allowing for sorting */
const double tentmap_const = 1.e6; //constant for the tent map

VecDim is the output vector dimension. The ideia is to iterate at least (tentmap_delay + VecDim) turns and write the result in retval (a vector of doubles).

To use this code:

vector<double> val;

val = GenRandRea(2, 10);
for (int kk=0; kk<10;kk++){
    cout << setprecision(9) << val[kk] << endl;
}

which will for example produce:

0.767902586 0.848146121 0.727780818 0.408328773 0.88750684 0.83126026 0.253109609 0.620335586 0.569496621 0.145755069

Regards!

查看更多
Fickle 薄情
3楼-- · 2020-04-24 17:42

"Seed" the random number generator by getting the number of seconds since midnight and then passing it in:

Random rand = new Random(secs);

This still does not generate perfectly random numbers, but should serve your purpose.

查看更多
疯言疯语
4楼-- · 2020-04-24 17:43

Very few "random" number generators are actually random. Almost all are pseudorandom, following a predictable sequence when started with the same seed value. Many pseudorandom number generators (PRNGs) get their seed from the date and time of their initial invocation. Others get their seed from a source of random data supplied by the operating system, which often is generated from outside sources (e.g., mouse motion, keyboard activity).

The right way to seed a good random number generator is to not seed it. Every good generator has a default mechanism to supply the seed, and it is usually much better than any you can come up with. The only real reason to seed the generator is if you actually want the same sequence of random numbers (e.g., when you're trying to repeat a process that requires randomness).

See http://msdn.microsoft.com/en-us/library/system.random.aspx for the details of the C# Random class, but basically, it uses a very well known and respected algorithm and seeds it with the date and time.

To answer your key question, just use rand.Next(min, max+1) and you'll always get a random sequence of numbers between min and max inclusive. The sequence will be the same every time you use the same seed. But rand = new Random() will use the current time, and as long as your program is invoked with some separation in time, they'll be different.

查看更多
趁早两清
5楼-- · 2020-04-24 17:43

I am not so conversant in C#. But I don't think this problem would occur in Java because the default constructor of Random class uses a seed based on current time and a unique count identifier.Below is code from java.util.Random class.

private static volatile long seedUniquifier = 8682522807148012L;
public Random() { this(++seedUniquifier + System.nanoTime()); }

If C# doesent support this out of box, you could use the above code to create a unique seed each time.

P.S: Note that since access to seedUniquifier is not synchronized, even though its volatile, there is a small possibility that same seeds are used for multiple Random objects. From javadoc of Random class:

"This constructor sets the seed of the random number generator to a value very likely to be distinct from any other invocation of this constructor."

查看更多
家丑人穷心不美
6楼-- · 2020-04-24 17:44

Producing the same sequence over and over is often a feature, not a bug, as long as you control it. Producing a repeatable sequence makes debugging easier. If you are serious about wanting a non-reproducible random sequence, you could look for a secure random number generator with this as a design aim. You've tagged your question C#, but since Java has http://docs.oracle.com/javase/1.4.2/docs/api/java/security/SecureRandom.html and the windows API has http://en.wikipedia.org/wiki/CryptGenRandom you may able to find an equivalent in C#.

查看更多
登录 后发表回答