Random numbers are deceptive,. Net, Java, C testify for me (go)

Source: Internet
Author: User

almost all programming languages provide a "generate a random number" method, that is, call this method will generate a number, we do not know in advance what the number it generates. For example, in. NET, write the following code:
Random rand = Newrandom (); Console.WriteLine (Rand. Next ());

After the run, the results are as follows:

The Next () method is used to return a random number. The same code you do is probably different from my results, and the result of my multiple runs is probably different, and that's the random number.

First, traps

Seemingly simple things, when used with traps. I write the following code to generate 100 random numbers:

for (int i=0;i<100;i++) {     random rand = new Random ();     Console.WriteLine (Rand. Next ()); }

Too strange, unexpectedly generated "random number" has a lot of continuous same, this is what "random number" ah. Someone is pointing out that "put new Random ()" Outside The For loop:

Random rand = Newrandom (); for (int i=0;i<100;i++) {                 Console.WriteLine (rand. Next ()); }

Operation Result:

I can do it!

Second, what is this for?

This starts with the principle that "random numbers" are generated in the computer. We know that the computer is very strict, under the determined input conditions, the result is only determined, not each execution of the results are not the same. So how do you use software to produce seemingly indeterminate random numbers?

There are many kinds of algorithms for generating random numbers, the simplest and most commonly used are "linear with congruential": Number of n+1 = (nth number *29+37)% 1000, where% is the "remainder" operator. A lot of people like me see the formula is a headache, I use the code to explain it, Myrand is a custom generated random number of the class:

Class Myrand {     private int seed;     public Myrand (int seed)    {     this.seed = seed;    }    public int Next ()    {      int next = (seed * + Notoginseng)%;      Seed = Next;      return next;   }  }

Call as follows:

Myrand rand = Newmyrand (51); for (int i = 0; i < i++)  {     Console.WriteLine (rand). Next ());  }

The results of the implementation are as follows:

The generated data is not looking "random". Simply explain this code: we create an object of Myrand, then the constructor passes a number 51, the number is assigned to seed, and each time the next method is called, a random number is calculated based on (seed * 29 + 37)% 1000, and the random number is assigned to seed. The resulting random number is then returned. So the next time you call next (), seed is no longer 51, but the last generated random number, which makes it seem as if each generated content is "random". Note that the purpose of the "%1000" redundancy budget is to ensure that the generated random number does not exceed 1000.

Of course, whether you run or I run each time, the output is the same random number, because according to the given initial data 51, we can infer in turn that all the "random number" generated below can be calculated. This initial data 51 is called "Random number Seed", this series of 516, 1, 66, 951, 616 ... Numbers are called "Random number sequences". If we change 51 to 52, we will have this result:

Third, the landlord of good people, kneeling to seek seeds

So how do you make a different "random number sequence" Every time you run a program? Because we are likely to be different each time we execute the program, we can do the "random number Seed" with the current time.

Myrand rand = Newmyrand (environment.tickcount); for (int i = 0; i < i++)  {     Console.WriteLine (rand). Next ());  }

Environment.tickcount is "the number of microseconds elapsed since the system started." So every time the program runs Environment.tickcount is unlikely to be the same (by hand who can start two times within a millisecond of the program), so each generation of random number is different.

Of course if we put new Myrand (Environment.tickcount) into the For loop:

for (int i = 0; i < i++)  {     Myrand rand = Newmyrand (environment.tickcount);     Console.WriteLine (Rand. Next ());  }

The result of the operation becomes "many is continuous", the principle is very simple: because the For loop body executes very quickly, so the time of each loop is probably also the same as the last (two lines of code runs less than one millisecond long event), because this time "random number Seed" Environment.tickcount Same as the last "random number seed", so that the first "random number" generated by next () is the same. From "320" to "856" is because the time elapsed a millisecond when running to "856".

Iv. realization of each language

We see. NET's random class has a constructor for the int type parameter:

Public Random (int Seed)

is to accept a "random number seed" Just like we wrote Myrand. The parameterless constructor we previously called was constructed for the passing of the Environment.tickcount class to random (int Seed), with the following code:

    Public Random (): This (environment.tickcount)        {        }

We finally understand the first doubts.

In the same way, generating 10 random numbers in C + + should not be called as follows:

int i; for (i=0;i<10;i++) {     srand ((unsigned) time (NULL));     printf ("%d\n", Rand ()); }

Instead, you should:

Srand ((unsigned) time (NULL)); Set the current time to "random number seed" int i; for (i=0;i<10;i++) {              printf ("%d\n", Rand ());}

Five, "Wonderful" Java

Java learners may ask a question, and in the lower Java version, the following will produce the same random number as in. Net, C + +:

for (int i=0;i<100;i++) {     random rand = new Random ();     System.out.println (Rand.nextint ()); }

Because the implementation of the parameterless constructor of the Rand class in the lower version of Java also uses the current time to seed:

Public Random () {This (System.currenttimemillis ());}

But in a higher version of Java, such as Java1.8, the "error" code above does not matter:

Why is it? Let's take a look at the implementation code for this random parameterless constructor:

Public Random () {This (Seeduniquifier () ^ system.nanotime ()),} <br>private static Long Seeduniquifier () {for (;;) {Long current = Seeduniquifier.get (), Long next = current * 181783497276652981L; if (Seeduniquifier.compareandset (Curren T, next)) return to Next;}   }  Privatestaticfinal atomiclong seeduniquifier  = new Atomiclong (8682522807148012L);

Instead of using the current time to do the "random number Seed", it uses System.nanotime (), which is the nanosecond-level amount of time, and uses the atomic weight Atomiclong to make the XOR of a number calculated from the last call to the constructor. For an explanation of this code, refer to this article, "decrypting a random number generator (2)--Seeing the linear congruence algorithm from Java source."

The most central place is to use the static variable Atomiclong to record the seed that is used each time the random constructor is called, and the next time you call the random constructor, avoid the same as last.

Problems in the system of six and high concurrency

We analyzed earlier that for random number generators that use system time to do "random number seed", if you want to generate multiple random numbers, be sure to share a "random number seed" to avoid generating random numbers for a short period of time to generate duplicate random numbers. However, in some high-concurrency systems, a non-attention will also create problems, such as a Web site on the server side by the following method to generate a verification code:

Random rand = new Random (); Int code = rand. Next ();

When the web site concurrency is very large, there may be a millisecond in a number of individual requests for verification code, which will cause these people to request the verification code is duplicated, will bring a potential vulnerability to the system.

Another example I saw today is an article, "When stochastic is not random: a lesson in online poker," It says, "since the seed of the random number generator is based on the server clock, hackers can reduce the likelihood of chaos to only 200,000 by synchronizing their programs with the server clock." By that time, once the hacker knew 5 cards, he could quickly search the 200,000 possible chaotic sequences in real time to find the kind of game. So once the hacker knows the two cards and 3 common cards in the hand, they can guess what cards will come from the turn and the river, and the other players ' cards. "

There are several workarounds for this scenario:

1. Use the random object as a global instance (static). Random in Java is thread-safe (locking handled internally);. NET random is not thread-safe and requires lock handling. However, locking can cause slow processing problems. And since the initial seed is deterministic, the attacker has the possibility of inferring a "random number seed" based on a number of random number sequences obtained.

2. Because the value of each GUID generated is not the same, some articles on the web say that you can create a GUID to calculate its hashcode or MD5 value to do the seed: New Random (Guid.NewGuid (). GetHashCode ()). But I think that the GUID generation algorithm is deterministic and can be predicted in case of sufficient conditions, so that the generated random number also has a predictable possibility. Of course it's just my guess, not the proof of the theory.

3. Use "True random number generator", look at the next section decomposition!

Seven, true random number generator

According to our previous analysis, we know that these so-called random numbers are not really "random", just look random, and therefore are called "pseudo-random algorithms". Some physical hardware is used to collect real random physical parameters in real life such as physical noise, cosmic rays, quantum decay, and so on, in some cases where the random requirements are high, to produce real random numbers.

Of course, there are smart people who have thought about generating random numbers without using the method of adding "random number generator" hardware. When we operate the computer, the movement of the mouse, the action of tapping the keyboard is unpredictable, the external command of the computer when to execute what process, processing what files, loading what data is also unpredictable, resulting in CPU speed, hard disk read and write behavior, memory occupancy changes are unpredictable. Therefore, if this information is collected as a random number seed, then the generated random number is not predictable.

The true random number generator with "/dev/random" can be used under Linux/unix, and its data master comes from the hardware interrupt information, but the speed of generating the random number is relatively slow.

Windows can call the system's CryptGenRandom () function, which is based on the current process ID, the current thread ID, the TickCount after system startup, the current time, the high performance counter value returned by QueryPerformanceCounter, The user name, computer name, CPU counter value, and so on to calculate. As with "/dev/random", the Generation of CryptGenRandom () is slower and consumes larger system resources.

Of course. NET can also use the RNGCryptoServiceProvider Class (under the System.Security.Cryptography namespace) to generate true random numbers, as described in StackOverflow previous post RNGCryptoServiceProvider not CryptGenRandom () function, but similar to the cryptgenrandom () principle.

Viii. Summary

Some people may ask: "/dev/random", CryptGenRandom () such as "True random number Generator", why also provide, use pseudo-random number such as "fake"? As mentioned earlier, the "/dev/random", CryptGenRandom () generation is slow and consumes more performance. In cases where the unpredictability of random numbers is low, the pseudo-random number algorithm can be used, because the performance is relatively high. True random number generators are used when the unpredictability of random numbers is high, and the hardware devices of true random number generators need to consider the cost problem, while "/dev/random" and CryptGenRandom () have poor performance.

Everything is not perfect, there is no absolute good, there is no absolute bad, this is a wonderful place in the multi-world.

From: Yang Zhengko-Blog Park

Links: http://www.cnblogs.com/rupeng/p/3723018.html

Random numbers are deceptive,. Net, Java, C testify for me (go)

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.