Java Little White Stepping on Pit Record-Random Secret

img

Are you going to write the lottery program for the company's annual meeting? Java programmers have to be careful, there are mysteries in obtaining random numbers.

How to get random numbers in Java?

There are many ways to obtain random numbers. Let's take a look at the two simplest ones first.

private static final Random rnd = new Random();
//第一种
static int random(int n) {
    return n>=0 ? rnd.nextInt(n) : rnd.nextInt(Math.abs(n));
}
//第二种
static int random2(int n) {
    return Math.abs(rnd.nextInt())%n;
}

Let's see what is the difference between the first type and the second type?

Is n’t it easy to see? Let's run a simple program to see:

public static void main(String[] args) {
    int n = 1000;
    int di = 0;
    int low = 0;
    for(int i = 0;i < 10_000_000;i++) {
        if(random(n) < Math.abs(n/2)) {
            di++;
        }
        
        if(random2(n) < Math.abs(n/2)) {
            low++;
        }
    }
    System.out.println(di);
    System.out.println(low);
}

We found that many of the numbers we tested are the same, do we think they are similar?

public static void main(String[] args) {        
    int n = 2*(Integer.MAX_VALUE/3);
    int di = 0;
    int low = 0;
    for(int i=0;i<10_000_000;i++) {
        if(random(n)<Math.abs(n/2)) {
            di++;
        }
        
        if(random2(n)<Math.abs(n/2)) {
            low++;
        }
    }
    System.out.println(di);
    System.out.println(low);
}

Run the data and see the results:

  • Random data is relatively uniform;

  • The data of random2 almost falls to 2/3 in the first half and only 1/3 in the second half.

Get to the bottom

nextInt () This method may look good, but there are three shortcomings.

The first disadvantage is: If n is a small power of 2, after a fairly short period, the random number it generates will repeat.

The second disadvantage is that if n is not a power of 2, then on average, some numbers will appear more frequently than others. In particular, n is relatively large, this shortcoming is very obvious. This is the reason why  2*(Integer.MAX_VALUE/3) there are 2 multiplications.

The third disadvantage is that in rare cases, it will return a number that falls outside the specified range or report an error. Examples are as follows:

public static void main(String[] args) {
    int n=Integer.MIN_VALUE;
    int di=0;
    int low=0;
    for(int i=0;i<10_000_000;i++) {
        if(random(n)<Math.abs(n/2)) {
            di++;
        }
        
        if(random2(n)<Math.abs(n/2)) {
            low++;
        }
    }
    System.out.println(di);
    System.out.println(low);
}

Error reason Math.abs () returns Integer.MIN_VALUE when it encounters Integer.MIN_VALUE. There is such a paragraph in the method description of abs:

Note that if the argument is equal to the value of {@link Integer#MIN_VALUE}, the most negative representable{@code int} value, the result is that same value, which is negative.

Note: In the Math.abs () method, if the input value is Integer.MIN_VALUE, then the same result will be returned.

On the other hand, you can also look at the code implementation of abs to understand

public static int abs(int a) { return (a < 0) ? -a : a; }

Suppose a = Integer.MIN_VALUE is -2147483648 (0x80000000), assuming that the return value of int 2147483648 will overflow, because the maximum value of int is 2147483647 (0x7fffffff), and after overflowing it becomes 0x80000000, namely Integer.MIN_VALUE

The source code is described in detail as follows:

/**
 * Returns the absolute value of an {@code int} value.
 * If the argument is not negative, the argument is returned.
 * If the argument is negative, the negation of the argument is returned.
 *
 * <p>Note that if the argument is equal to the value of
 * {@link Integer#MIN_VALUE}, the most negative representable
 * {@code int} value, the result is that same value, which is
 * negative.
 *
 * @param a the argument whose absolute value is to be determined
 * @return the absolute value of the argument.
 */
 public static int abs(int a) {
 	return (a < 0) ? -a : a;
 }

The Java class library provides a method with seeds to solve the above problem, which is Random.nextInt (n).

to sum up

The random number generator involves a lot of knowledge about algorithms. Fortunately, we do n’t need to do this work ourselves. We can use the ready-made results for our use, such as Random.nextInt (n) or java.security.SecureRandom , Or a third-party API. Note: We try to use the class library instead of developing it ourselves.

Linux systems have / dev / random, / dev / urandom to provide users with true random numbers.

1006 original articles were published · praised 1891 · 900,000 views

Guess you like

Origin blog.csdn.net/Dream_Weave/article/details/105539630