Pthon Learning Notes - Random Number Advancement

Posted by stokie-rich on Tue, 11 Jun 2019 21:51:11 +0200

Do you really understand random numbers?

Author : Jasper Yang
School : Bupt

Q: Why did you write this article?
A: Because I found that in recent scientific calculations, we often encounter random numbers. All random numbers are based on 0,1 random. How can this 0,1 random be realized? Next I'll talk about it.~

This article is different from the stray technical articles on the internet. I'm investigating random ly, and I'm going to put all the relevant knowledge in order. I hope everyone can get a little promotion after reading it.~

& What is Random Number

Random Numbers: Mathematically generated are all pseudo-random numbers. Real random numbers are generated by physical methods.

Random Number Seeds: Random Numbers are generated by arithmetic rules. In c++, the random number seeds of srand(seed) are different, and the random number values of rand() are different. If the seeds of random number are the same each time, the value of rand() is the same. So in order to generate random numbers, the seeds of srand(seed) random numbers must also be random. In python, random.seed() is used to set seeds.

Next, I will talk about not only the principle of random number generation, but also how to realize it in python and c ++. Of course, most of the information is also found online. I just made a summary and described it in my own language.

& The Principle of Random Number

Here I read a blog, because this blog is the blogger to turn, but the blogger did not indicate where to turn from, I do not po ol out links, you look down.~

A friend asked the blogger about a program error.

C/C++ code
for (int i =0;i< n;++i)
{
    srand((unsigned)time( NULL )); 
    int r = rand()%100;
    cout << r << ",";
}

It's obvious here that he wants to output a random sequence of numbers less than 100. But the result of the operation is a sequence like 97, 97, 97,... 97, 30, 30, 30, 30, 30, 30, 30,..., 27, 27, 27, 27, 27,.... It's obvious that there's no randomness at all. It's because he doesn't understand the rand function of C. And I also saw the wrong usage of C Several similar misuses (rand of C and C) are similar in principle. Think about how many similar mistakes you made when you first started learning. So I went down to check my materials and summarized some wrong uses of random number. I hope it will be helpful for beginners.

Nowadays, the "random number" produced by the generating function of random number in various languages is actually called "pseudo-random number".
The whole function of random numbers is considered as an expression:

$$A = R(s)$$

R is a random function, s is a seed. A is a sequence. That is to say, for any seed s, after R calculation, there is always a certain sequence A corresponding to it. When var rnd = new Random (s) is called in C # or s Rand (s) is called in C, one of the essentially tasks is to set the seed. And rnd.Next(); or rand() is just the next element on A. Of course, the actual implementation. It is impossible to calculate a sequence A in advance, so rand() is equivalent to the next number s'calculated by s, then s' is assigned to s as a new seed, and finally s'is returned as a result.

To go into detail, that's it.

If agreed: $a_1 = f (seed), a {n + 1} = f (an)$
Then you can go to a sequence: $a_1,a_2,a_3...a_n$, so to make a pseudo-random function rand, just let it return the next element of the sequence every time it calls.

Here are two common mistakes

C# code
for (int i=0;i<n;++i)
{
    var rnd = new Random (s);//s is a number determined first in fact
    Console.Write ("{0},",rnd.Next());
}

In this way, every time Random is used, a variable RND is applied for, and then the variable is used to find the random number (rnd.Next()). In fact, we are always looking for the first one in the sequence of random numbers. In this way, the first number must be fixed, and there is no random number.

The second is more common.

C# code
for (int i=0;i<n;++i)
{
    var rnd = new Random ();//Use System Time as Seed
    Console.Write ("{0},",rnd.Next());
}

In the first case, we used a fixed constant s to seed. We chose the system time to seed, in order to achieve a random effect, but the result would be 97, 97, 97,... 97, 30, 30, 30, 30, 30, 30,... 27, 27, 27, 27,... The same result as that of the blogger's friend.

This is because the clock update frequency of Windows system is about 10 ms. And this for loop is obviously faster to execute.
Much more. So either Environment.TickCount (Random's default seed) or C's time function returns the same value over a period of execution time, resulting in rnd.Next returning a constant over a period of time.

So the right thing to do is to move the seeds out of the cycle.

C# code
var rnd = new Random ();//Use System Time as Seed
for (int i=0;i<n;++i)
{
    Console.Write ("{0},",rnd.Next());
}

How to implement random numbers in various libraries?
The implementation under Linux is similar to the following

static unsigned long next = 1;

/* RAND_MAX assumed to be 32767 */
int myrand(void) {
    next = next * 1103515245 + 12345;
    return((unsigned)(next/65536) % 32768);
}

void mysrand(unsigned seed) {
    next = seed;
}

myrand and mysrand correspond to rand and srand respectively, but the actual implementation of rand will be more complex.

Here's how the blogger implemented it. It's actually quite simple. Each of us can implement a random number method we want to add to our private library.~

*
 * Copyright (c) 2008 Microsoft::Tsorgy.Utils, Reserved.
 * 
 * Filename:    @(#)Random.cs
 * Create by:   TsOrgY
 * Email:       tsorgy@gmail.com
 * Date:        2008/12/27 15:01:40
 * 
 * Classname:   Random
 * Description: A device that generates a sequence of numbers that meets certain stochastic statistical requirements.
 *              
 */
using System;
using System.Runtime.InteropServices;
namespace Tsorgy.Utils {
    /// <summary>
    /// Represents a pseudo-random number generator, a device that generates a sequence of numbers that meets certain stochastic statistical requirements.
    /// </summary>
    [Serializable]
    [ComVisible(true)]
    public class Random {
        private int inext;
        private int inextp;
        private const int MBIG = 0x7fffffff;
        private const int MSEED = 0x9a4ec86;
        private const int MZ = 0;
        private int[] SeedArray;
        /// <summary>
        /// Initialize a new instance of the Random class using the default seed value associated with time.
        /// </summary>
        public Random()
            : this(Environment.TickCount) {
        }
        /// <summary>
        /// Initializes a new instance of the System.Random class with the specified seed value.
        /// </summary>
        /// The number < param name= "Seed"> used to calculate the starting value of a sequence of pseudorandom numbers. If a negative number is specified, its absolute value is used. </param>
        /// <exception cref="System.Overflow Exception">Seed is System.Int32.MinValue, which causes overflow when calculating its absolute value. </exception>
        public Random(int Seed) {
            this.SeedArray = new int[0x38];
            int num2 = 0x9a4ec86 - Math.Abs(Seed);
            this.SeedArray[0x37] = num2;
            int num3 = 1;
            for (int i = 1; i < 0x37; i++) {
                int index = (0x15 * i) % 0x37;
                this.SeedArray[index] = num3;
                num3 = num2 - num3;
                if (num3 < 0) {
                    num3 += 0x7fffffff;
                }
                num2 = this.SeedArray[index];
            }
            for (int j = 1; j < 5; j++) {
                for (int k = 1; k < 0x38; k++) {
                    this.SeedArray[k] -= this.SeedArray[1 + ((k + 30) % 0x37)];
                    if (this.SeedArray[k] < 0) {
                        this.SeedArray[k] += 0x7fffffff;
                    }
                }
            }
            this.inext = 0;
            this.inextp = 0x15;
            Seed = 1;
        }
        private double GetSampleForLargeRange() {
            int num = this.InternalSample();
            if ((((this.InternalSample() % 2) == 0) ? 1 : 0) != 0) {
                num = -num;
            }
            double num2 = num;
            num2 += 2147483646.0;
            return (num2 / 4294967293);
        }
        private int InternalSample() {
            int inext = this.inext;
            int inextp = this.inextp;
            if (++inext >= 0x38) {
                inext = 1;
            }
            if (++inextp >= 0x38) {
                inextp = 1;
            }
            int num = this.SeedArray[inext] - this.SeedArray[inextp];
            if (num < 0) {
                num += 0x7fffffff;
            }
            this.SeedArray[inext] = num;
            this.inext = inext;
            this.inextp = inextp;
            return num;
        }
        /// <summary>
        /// Returns a nonnegative random number.
        /// </summary>
        /// <returns>32-bit signed integers greater than or equal to zero and less than System.Int32.MaxValue. </returns>
        public virtual int Next() {
            return this.InternalSample();
        }
        /// <summary>
        /// Returns a nonnegative random number less than the specified maximum.
        /// </summary>
        /// <param name="maxValue">The upper bound of the random number to be generated (the upper bound cannot be taken for the random number). MaxValue must be greater than or equal to zero. </param>
        /// <returns> A 32-bit signed integer greater than or equal to zero and less than maxValue, i.e., the range of returned values includes zero but does not include maxValue. </returns>
        /// <exception cref="System.ArgumentOutOfRangeException">maxValue is less than zero. </exception>
        public virtual int Next(int maxValue) {
            if (maxValue < 0) {
                throw new ArgumentOutOfRangeException("maxValue", string.Format("'{0}' must be greater than zero.", maxValue));
            }
            return (int) (this.Sample() * maxValue);
        }
        /// <summary>
        /// Returns a random number in a specified range.
        /// </summary>
        /// The lower bound of the random number returned by <param name="minValue"> (the lower bound value of the random number can be taken). </param>
        /// The upper bound of the random number returned by <param name="maxValue"> (the upper bound cannot be taken for the random number). MaxValue must be greater than or equal to minValue. </param>
        /// <returns>A 32-bit signed integer greater than or equal to minValue and less than maxValue, i.e., the range of returned values includes minValue but not maxValue. If minValue equals maxValue, minValue is returned. </returns>
        /// <exception cref="System.ArgumentOutOfRangeException">minValue is larger than maxValue. </exception>
        public virtual int Next(int minValue, int maxValue) {
            if (minValue > maxValue) {
                throw new ArgumentOutOfRangeException("minValue", string.Format("'{0}' cannot be greater than {1}.", minValue, maxValue));
            }
            long num = maxValue - minValue;
            if (num <= 0x7fffffffL) {
                return (((int) (this.Sample() * num)) + minValue);
            }
            return (((int) ((long) (this.GetSampleForLargeRange() * num))) + minValue);
        }
        /// <summary>
        /// Fill the elements of the specified byte array with random numbers.
        /// </summary>
        /// <param name="buffer"> byte array containing random numbers. </param>
        /// <exception cref="System.ArgumentNullException">buffer is null. </exception>
        public virtual void NextBytes(byte[] buffer) {
            if (buffer == null) {
                throw new ArgumentNullException("buffer");
            }
            for (int i = 0; i < buffer.Length; i++) {
                buffer[i] = (byte) (this.InternalSample() % 0x100);
            }
        }
        /// <summary>
        /// Returns a random number between 0.0 and 1.0.
        /// </summary>
        /// Double-precision floating-point numbers < returns > greater than or equal to 0.0 and less than 1.0. </returns>
        public virtual double NextDouble() {
            return this.Sample();
        }
        /// <summary>
        /// Returns a random number between 0.0 and 1.0.
        /// </summary>
        /// Double-precision floating-point numbers < returns > greater than or equal to 0.0 and less than 1.0. </returns>
        protected virtual double Sample() {
            return (this.InternalSample() * 4.6566128752457969E-10);
        }
    }
}

Here I want to mention another thing that you have heard many times - --------> Linear congruence method.

This is also a way to achieve random numbers.

Linear congruence method (LCG)

Its recursive formula:

$$N_{j+1} = (A * N_j +B) (mod M)$$

A, B and M are the constants set by the generator.

The maximum period of LCG is M, but in most cases it is less than M. To maximize the LCG cycle, the following conditions should be met:

  1. B,M mutual prime

  2. The product of all the prime factors of M divides A-1

  3. If M is a multiple of 4, so is A-1.

  4. A,B,$N_0 $are smaller than M.

  5. A,B are positive integers

Finally, a <$N_i$> sequence is generated, which should satisfy the following conditions.

  1. This function should be a full cycle generating function. That is to say, this function should produce all the numbers between 0 and m before repeating.

  2. The resulting sequence should look random

  3. This function should be implemented efficiently with 32 bit arithmetic

Realization

#include <stdio.h>  
#include <time.h>  
static unsigned long rand_seed;  
void mysrand (unsigned long int);  
void myrand ();  
int  
main (void)  
{  
    int i;  
  
    mysrand (time (NULL));  
    for (i = 0; i < 100; i++)  
      {  
          myrand ();  
      }  
    return 0;  
}  
  
void  
mysrand (unsigned long seed)  
{  
    rand_seed = seed;  
}  
  
void  
myrand ()  
{  
    rand_seed = (rand_seed * 16807L) % ((1 << 31) - 1);  
    printf ("%ld ", rand_seed);  
}  

As you can see, this implementation is very similar to the implementation of linux mentioned above, but in fact it is the same.

& Random Number Use

Because there are a lot of c++ and python that have been used recently (I think these two languages are the two most needed languages for programmers to master, and the rest are supplements). So I'll just talk about the implementation of these two languages.

c++

Instance Program

#include "stdafx.h"
#include <time.h>
#include <stdlib.h>
int _tmain(int argc, _TCHAR* argv[])
{
 // Initialization of Random Number Seeds
 // The time function returns the time elapsed so far, in seconds, from 0:00 to 0:00 on January 1, 1970.
 srand((int)time(NULL));
 int j;
 for (int i = 0; i < 10; i++) {
  j = (rand() * 10) / RAND_MAX + 1; // Generating Random Numbers between 1 and 10
  printf("j = %d \n", j);
 }
 unsigned start = (rand() * 1000)/ RAND_MAX + 15550; // Generating Random Numbers between 15550 and 16549
 printf("start = %d \n", start);
 start &= ~1; // Change start to an even number, and if it's an odd number, start to an even number of start - 1
 printf("start = %d \n", start);
 getchar();
 return 0;
}

c + + is actually two functions of srand and rand.
All of the above are generated integers. If you need floating-point numbers or something, you need to deal with them by yourself. In python, there are many functions.

python

The content of this section is Capricorn's Laboratory Tidy up. Actually, this piece of content can be translated directly to the doc on the official website, but I am a little lazy and don't want to see it, so I use the content of this blog article.~

<h3>random.random</h3>
random.random() is used to generate a number of random characters from 0 to 1: 0 <= n < 1.0

<h3>random.uniform</h3>

The function prototype of random.uniform is random.uniform(a, b), which is used to generate a random number within a specified range. One of the two parameters is the upper limit and the other is the lower limit. If a > b, the generated random number n: a <= n <== B. If $a < B $, then B <= n <== a.

<h3>random.randint</h3>

The function prototype of random.randint() is random.randint(a, b), which is used to generate an integer in a specified range. The parameter a is the lower limit and the parameter B is the upper limit. The random number n: a <= n <= B is generated.

<h3>random.randrange</h3>

The function prototype of random.randrange is random.randrange([start], stop[, step]). It obtains a random number from a set that increases by a specified Radix within a specified range. For example: random.randrange(10, 100, 2), the result is equivalent to getting a random number from [10, 12, 14, 16,... 96, 98] sequence. Randrange (10, 100, 2) is equivalent to random.choice(range(10, 100, 2).

<h3>random.choice</h3>

random.choice takes a random element from the sequence. Its function prototype is random.choice(sequence). The parameter sequence represents an ordered type. Here's a note: sequence is not a specific type in python, but refers to a series of types in general. list, tuple, and strings all belong to sequence. For sequence, you can see the chapter on Python manual data model. Here are some examples of using choice:

print random.choice("Study Python")   
print random.choice(["JGood", "is", "a", "handsome", "boy"])  
print random.choice(("Tuple", "List", "Dict"))  

<h3>random.shuffle</h3>

The function prototype of random.shuffle is random.shuffle(x[, random]), which is used to scramble elements in a list.

<h3>random.sample</h3>

The function prototype of random.sample is random.sample(sequence, k), which randomly retrieves fragments of specified length from a specified sequence. The sample function does not modify the original ordered column.

OK, it's over. Friends, do you think you've made a little progress?~

paper done 2017/05/13

Topics: Python less Linux Windows