Simulation of wechat red envelope grabbing by double mean method in java

Posted by Bullit on Sat, 26 Feb 2022 12:27:48 +0100

preface

When it comes to robbing red envelopes, you must be very familiar with it, especially wechat robbing red envelopes, which we contact almost every day. Although the amount of red envelopes we grab each time varies from big to small, we are deeply immersed in the happiness of grabbing red envelopes 😄. But then again, I wonder if you guys have thought about what algorithm is used to grab red envelopes? How is it achieved? Today, let's find out

Grab a red envelope

Now the red envelopes we distribute are nothing more than two forms: hard luck red envelopes and fixed amount red envelopes. The number of fixed amount red envelopes can be one or more, and the amount in each red envelope is the same, so there is no need to use too many algorithms to calculate the red envelope amount, which is relatively simple; The lucky red envelope is relatively complex. It needs to calculate the amount of each red envelope and ensure that each red envelope is as fair as possible, which requires a higher algorithm. By consulting Baidu and friends who have realized the red envelope function, we know that the algorithm with high frequency is the double mean method. Next, we will use the double mean method to simulate the red envelope function 👇

Simulation of red envelope grabbing by double mean method

First, let's take a look at the functional requirements of the lucky red envelope:

  • The cumulative amount of all red envelopes is equal to the total amount of red envelopes
  • The amount of each red envelope cannot be less than 0.01 yuan, which means that each user must be able to grab at least a preset minimum amount. The minimum amount set for RMB red envelopes is generally 0.01 yuan. If other types of red envelopes are issued (such as points, other types of currencies, etc.), you need to customize a minimum amount
  • The expected return of grabbing red envelopes should be independent of the order, that is, the amount of each red envelope is independent of the order of grabbing red envelopes, so as to ensure the fairness of red envelopes as far as possible

Before realizing the above functional requirements, we also need to know what is the double mean method 👇

Assuming that the total amount of red envelopes is X, the number of red envelopes is Y, and the minimum amount of each red envelope is 0.01 yuan, the range of red envelope amount each time is between (0.01, (X/Y) *2).

Let's take a specific example. If 10 people come to grab a red envelope with an amount of 100 yuan, it can be concluded from the above formula that the amount range of the first person is between (0.01, 20). According to the normal distribution, the amount of the first person should be about 10 yuan, and the probability of being far less than 10 yuan and far more than 10 yuan will be very low, Here, let's assume that the first person grabs 10 yuan; At this time, the second person comes to grab the red envelope. There is 90 yuan left in the red envelope. According to the formula, the amount range of the red envelope grabbed by the second person is also between (0.01 and 20). By analogy, we can see that the amount of red envelopes robbed by each person is about 10 yuan, and the probability of far less than 10 yuan and far more than 10 yuan will be very low, so as to ensure that the amount robbed by each person is similar as much as possible.

Next, let's look at the specific code 👇

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Random;

/**
 * Simulation of wechat red envelope grabbing by double mean method
 * @description: RedEnvelope
 * @author: Zhuang ba liziye
 * @create: 2022-02-15 14:43
 **/
public class RedEnvelope {
    public static void main(String[] args) {
        long startTime=System.currentTimeMillis();
        //Initialize the test scenario and simulate four situations:
        //10 people grab 0.1 yuan red envelope
        //10 people grab 1 yuan red envelope
        //10 people grab 10 yuan red envelopes
        //10 people grab 100 yuan red envelopes
        BigDecimal[][] scene = {
                {new BigDecimal("0.1"), new BigDecimal("10")},
                {new BigDecimal("1"), new BigDecimal("10")},
                {new BigDecimal("10"), new BigDecimal("10")},
                {new BigDecimal("100"), new BigDecimal("10")}
        };
        //Set the minimum amount of each red envelope to 0.01 yuan
        BigDecimal min = new BigDecimal("0.01");
        //Test each red envelope separately
        for (BigDecimal[] decimals : scene) {
            final BigDecimal amount = decimals[0];
            final BigDecimal num = decimals[1];
            System.out.println("=====" + num + "One person grabs one"+ amount + "Yuan red envelope" + "=====");
            GrabRedEnvelope(amount, min, num);
        }
        long endTime=System.currentTimeMillis();
        System.out.println("Program run time: " + (endTime - startTime) + "ms");
    }

    //Simulate the process of grabbing red envelopes
    private static void GrabRedEnvelope(BigDecimal amount, BigDecimal min, BigDecimal num){
        BigDecimal remain = amount.subtract(min.multiply(num));
        final Random random = new Random();
        final BigDecimal hundred = new BigDecimal("100");
        final BigDecimal two = new BigDecimal("2");
        BigDecimal sum = BigDecimal.ZERO;
        BigDecimal redpeck;
        for (int i = 0; i < num.intValue(); i++) {
            final int nextInt = random.nextInt(100);
            if(i == num.intValue() -1){
                redpeck = remain;
            }else{
                //RoundingMode.CEILING: take the nearest integer on the right
                //RoundingMode.FLOOR: take the nearest positive number on the left
                redpeck = new BigDecimal(nextInt).multiply(remain.multiply(two).divide(num.subtract(new BigDecimal(i)),2, RoundingMode.CEILING)).divide(hundred,2, RoundingMode.FLOOR);
            }
            if(remain.compareTo(redpeck) > 0){
                remain = remain.subtract(redpeck);
            }else{
                remain = BigDecimal.ZERO;
            }
            sum = sum.add(min.add(redpeck));
            System.out.println("The first"+(i+1)+"The amount of red envelopes seized by individuals is:"+min.add(redpeck));
        }
        System.out.println("Whether the cumulative amount of all red envelopes is equal to the total amount of red envelopes:"+compare(amount, sum));
    }

    private static boolean compare(BigDecimal a, BigDecimal b){
        if(a.compareTo(b) == 0){
            return true;
        }
        return false;
    }
}

Let's look at the execution results of the code 👇

=====10 people grab a red envelope of 0.1 yuan=====

The amount of red envelope snatched by the first person is 0.01

The amount of red envelope snatched by the second person is 0.01

The amount of red envelope snatched by the third person is 0.01

The amount of red envelope snatched by the fourth person is 0.01

The amount of red envelope snatched by the fifth person is 0.01

The amount of red envelope snatched by the sixth person is 0.01

The amount of red envelope snatched by the seventh person is 0.01

The amount of red envelope snatched by the 8th person is 0.01

The amount of red envelope snatched by the 9th person is 0.01

The amount of red envelope snatched by the 10th person is 0.01

Whether the cumulative amount of all red envelopes is equal to the total amount of red envelopes: true

=====Ten people grab a 1 yuan red envelope=====

The amount of red envelope snatched by the first person is 0.06

The amount of red envelope snatched by the second person is 0.11

The amount of red envelope snatched by the third person is 0.14

The amount of red envelope snatched by the fourth person is 0.10

The amount of red envelope snatched by the fifth person is 0.06

The amount of red envelope snatched by the sixth person is 0.06

The amount of red envelope snatched by the seventh person is 0.10

Whether the cumulative amount of all red envelopes is equal to the total amount of red envelopes: true

=====Ten people grab a 10 yuan red envelope=====

The amount of red envelope snatched by the first person is 1.61

The amount of red envelope snatched by the second person is 1.08

The amount of red envelope snatched by the third person is: 1.45

The amount of red envelope snatched by the fourth person is: 1.35

The amount of red envelope snatched by the fifth person is 1.02

The amount of red envelope snatched by the sixth person is 0.57

The amount of red envelope snatched by the seventh person is 0.11

The amount of red envelope snatched by the 8th person is: 1.16

The amount of red envelope snatched by the ninth person is 1.31

The amount of red envelope snatched by the 10th person is 0.34

Whether the cumulative amount of all red envelopes is equal to the total amount of red envelopes: true

=====Ten people grab a red envelope of 100 yuan=====

The amount of red envelope snatched by the first person is: 10.19

The amount of red envelope snatched by the second person is 9.38

The amount of red envelope snatched by the third person is: 14.47

The amount of red envelope snatched by the fourth person is 2.08

The amount of red envelope snatched by the fifth person is 2.98

The amount of red envelope snatched by the sixth person is: 12.42

The amount of red envelope snatched by the seventh person is: 13.81

The amount of red envelope snatched by the 8th person is 19.87

The amount of red envelope snatched by the ninth person is 8.58

The amount of red envelope snatched by the 10th person is 6.22

Whether the cumulative amount of all red envelopes is equal to the total amount of red envelopes: true

Program running time: 6ms

We can see from the execution results that the double mean method ensures that the amount of each red envelope is roughly similar as much as possible. Of course, this algorithm can not be absolutely fair. Take 10 people grabbing a red envelope with an amount of 100 yuan as an example. If the first person grabs 15 yuan at this time, the range of red envelope amount of the second person becomes (0.01, 18.88). If the second person grabs a high amount at this time, it is unfavorable to the people behind. As in the above execution results, 10 people grabbed 100 yuan red envelopes, some grabbed 16.58 and others grabbed 0.26 😂.

In addition to the double mean method, there is another interesting algorithm - secant method. Let's take a simple look at what secant method is 👇

Simulation of red envelope grabbing by secant method

As the name suggests, the secant method regards the total amount of the red envelope as a rope when calculating, and then cuts the rope. The length of each rope represents the amount of each red envelope.

For example: now 10 people grab a 10 yuan red envelope, then there are 9 random numbers with an interval greater than or equal to 0.01 in the range of (0, 10). Assuming that the 9 division numbers are [1,1.6,2,3,4,5,6,7,8], then the amount of each red envelope is 1, 0.6, 0.4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2.

Let's take a look at the specific code 👇

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Random;

/**
 * Simulate wechat to grab red envelopes through secant method
 * @description: RedEnvelope
 * @author: Zhuang ba liziye
 * @create: 2022-02-15 14:43
 **/
public class RedEnvelope {
    public static void main(String[] args) {
        long startTime=System.currentTimeMillis();
        //Initialize the test scenario and simulate four situations:
        //10 people grab 0.1 yuan red envelope
        //10 people grab 1 yuan red envelope
        //10 people grab 10 yuan red envelopes
        //10 people grab 100 yuan red envelopes
        BigDecimal[][] scene = {
                {new BigDecimal("0.1"), new BigDecimal("10")},
                {new BigDecimal("1"), new BigDecimal("10")},
                {new BigDecimal("10"), new BigDecimal("10")},
                {new BigDecimal("100"), new BigDecimal("10")}
        };
        //Set the minimum amount of each red envelope to 0.01 yuan
        BigDecimal min = new BigDecimal("0.01");
        //Test each red envelope separately
        for (BigDecimal[] decimals : scene) {
            final BigDecimal amount = decimals[0];
            final BigDecimal num = decimals[1];
            System.out.println("=====" + num + "One person grabs one"+ amount + "Yuan red envelope" + "=====");
            GrabRedEnvelope(amount, min, num);
        }
        long endTime=System.currentTimeMillis();
        System.out.println("Program run time: " + (endTime - startTime) + "ms");
    }

    //Simulate the process of grabbing red envelopes
    private static void GrabRedEnvelope(BigDecimal amount,BigDecimal min ,BigDecimal num){
        final Random random = new Random();
        final int[] rand = new int[num.intValue()];
        BigDecimal sum1 = BigDecimal.ZERO;
        BigDecimal redpeck ;
        int sum = 0;
        for (int i = 0; i < num.intValue(); i++) {
            rand[i] = random.nextInt(100);
            sum += rand[i];
        }
        final BigDecimal bigDecimal = new BigDecimal(sum);
        BigDecimal remain = amount.subtract(min.multiply(num));
        for (int i = 0; i < rand.length; i++) {
            if(i == num.intValue() -1){
                redpeck = remain;
            }else{
                redpeck = remain.multiply(new BigDecimal(rand[i])).divide(bigDecimal,2,RoundingMode.FLOOR);
            }
            if(remain.compareTo(redpeck) > 0){
                remain = remain.subtract(redpeck);
            }else{
                remain = BigDecimal.ZERO;
            }
            sum1= sum1.add(min.add(redpeck));
            System.out.println("The first"+(i+1)+"The amount of red envelopes seized by individuals is:"+min.add(redpeck));
        }

        System.out.println("Whether the cumulative amount of all red envelopes is equal to the total amount of red envelopes:" + compare(amount, sum1));
    }

    private static boolean compare(BigDecimal a, BigDecimal b){
        if(a.compareTo(b) == 0){
            return true;
        }
        return false;
    }
}

Next, let's look at the implementation results of secant method 👇

=====10 One person grabs a 0.1 Yuan red envelope=====
The amount of red envelope snatched by the first person is: 0.01
 The amount of red envelope snatched by the second person is: 0.01
 The amount of red envelope snatched by the third person is: 0.01
 The amount of red envelope snatched by the fourth person is: 0.01
 The amount of red envelope snatched by the fifth person is: 0.01
 The amount of red envelope snatched by the 6th person is: 0.01
 The amount of red envelope snatched by the 7th person is: 0.01
 The amount of red envelope snatched by the 8th person is: 0.01
 The amount of red envelope snatched by the 9th person is: 0.01
 The amount of red envelope snatched by the 10th person is: 0.01
 Whether the cumulative amount of all red envelopes is equal to the total amount of red envelopes: true
=====10 One person grabs a 1 yuan red envelope=====
The amount of red envelope snatched by the first person is: 0.07
 The amount of red envelope snatched by the second person is: 0.12
 The amount of red envelope snatched by the third person is: 0.01
 The amount of red envelope snatched by the fourth person is: 0.10
 The amount of red envelope snatched by the fifth person is: 0.10
 The amount of red envelope snatched by the 6th person is: 0.08
 The amount of red envelope snatched by the 7th person is: 0.06
 The amount of red envelope snatched by the 8th person is: 0.06
 The amount of red envelope snatched by the 9th person is: 0.04
 The amount of red envelope snatched by the 10th person is: 0.36
 Whether the cumulative amount of all red envelopes is equal to the total amount of red envelopes: true
=====10 One person grabs a 10 yuan red envelope=====
The amount of red envelope snatched by the first person is: 1.19
 The amount of red envelope snatched by the second person is: 1.01
 The amount of red envelope snatched by the third person is: 0.60
 The amount of red envelope snatched by the fourth person is: 0.69
 The amount of red envelope snatched by the fifth person is: 0.66
 The amount of red envelope snatched by the 6th person is: 0.44
 The amount of red envelope snatched by the 7th person is: 0.39
 The amount of red envelope snatched by the 8th person is: 0.62
 The amount of red envelope snatched by the 9th person is: 0.41
 The amount of red envelope snatched by the 10th person is: 3.99
 Whether the cumulative amount of all red envelopes is equal to the total amount of red envelopes: true
=====10 One person grabs a red envelope of 100 yuan=====
The amount of red envelope snatched by the first person: 17.51
 The amount of red envelope snatched by the second person is: 14.62
 The amount of red envelope snatched by the third person is: 2.47
 The amount of red envelope snatched by the fourth person is: 4.19
 The amount of red envelope snatched by the fifth person is: 8.63
 The amount of red envelope snatched by the 6th person is: 0.01
 The amount of red envelope snatched by the 7th person is: 0.23
 The amount of red envelope snatched by the 8th person is: 6.15
 The amount of red envelope snatched by the 9th person is: 3.66
 The amount of red envelope snatched by the 10th person is 42.53
 Whether the cumulative amount of all red envelopes is equal to the total amount of red envelopes: true
 Program: run time 11 ms

Through the execution results, we can see that the randomness of the secant method is relatively large, which can not guarantee that the amount of each red envelope is roughly similar (10 people grab a red envelope of 100 yuan, and others will grab 0.01, which should not annoy others 😂); Moreover, the performance of secant method is not very good. Although the above code shows that the execution time of double mean method and secant method is not much different, when there are a large number of red envelopes to be calculated in the production environment, the gap must be huge. Therefore, when we want to realize the function of grabbing red envelopes, we must carefully consider and choose an algorithm that can not only ensure the similarity of the amount, but also ensure high efficiency~

Summary

My experience is limited, and some places may not be particularly good. If you have any questions when reading, please leave a message in the comment area, and we will discuss it later 🙇 ‍

Topics: Java wechat