|
微信发红包的金额总是不固定的,因此今天特意好奇一下,能不能使用Java代码进行模仿呢?
以下是完整的代码演示,如果不需要其中的数据分析,可以去掉,去掉之后的jdk版本不做过多的要求,没去掉之前,要求是1.8+:
package com.demo;
import java.util.Arrays;
/**
* 大致模仿微信发红包的金额
* @author 小书包
* @date 2018年10月13日13:26:32
*/
public class RedPocket {
/**
* 红包的初始化,每位用户分配到的为平均金额
* @param money 总金额
* @param pocketNum 红包数量
* @param current 当前是第几次
*/
private double[] calcuPocket(double money, int pocketNum) {
if ((pocketNum + 1) * 0.01 >= money) {
System.out.println("红包的最低金额为0.01元");
return null;
}
// 用于存储当前已分配的金额总数
double sum = 0;
double[] pockets = new double[pocketNum];
// 进行红包金额的初始化,每个人给出的金额为平均值
for (int i = 0; i < pocketNum; i++) {
pockets[i] = (double) Math.round((money / pocketNum) * 100) / 100;
// 出现这个判断是为了防止有的数除不掉,发的红包与金额总数不匹配,因此将最后剩下的全给最后一个
if (i == pocketNum - 1) {
pockets[i] = (double) Math.round((money - sum) * 100) / 100;
}
sum = sum + pockets[i];
}
return pockets;
}
/**
* 分析平均值的分布规律和方差的大致的分布
* @param current 当前位置
* @param pockets 红包数组
* @param average 平均值
*/
private void analysisByMathMethod(int current, double[] pockets, double average) {
System.out.print("第" + current + "次:");
int count = 0;
for (double pocket : pockets) {
System.out.print(pocket + " ");
if (pocket == average)
count++;
}
System.out.print("\t平均值为:" + average);
System.out.print("\t获得最小值为:" + Arrays.stream(pockets).reduce(Double::min).getAsDouble());
System.out.print("\t获得最大值为:" + Arrays.stream(pockets).reduce(Double::max).getAsDouble());
System.out.print("\t存在" + count + "个与平均值相同的元素!");
double result = calcuVariance(average, pockets);
System.out.print("\t方差为:" + result);
System.out.println();
}
/**
* 传递一个平均值和数组,用以计算数组中的值的方差分布
* @param average 平均值
* @param pockets 待计算方差的数组
* @return
*/
private double calcuVariance(double average, double[] pockets) {
double result = 0;
for (double pocket : pockets) {
result = result + Math.pow(pocket - average, 2);
}
result = result / pockets.length;
return result;
}
/**
* 随机进行红包的分布
* @param pockets 存放红包的数组
* @return
*/
private double[] changePosition(double[] pockets) {
int length = pockets.length;
// 表示当前的次数,用于计算需要随机多少次,随机次数越多,方差越大
int count = 0;
while (count < length * 10) {
// 随机从数组中挑选一个进行金额的减少
int start = (int) (Math.random() * length);
// 随机从数组中挑选一个进行金额的添加
int end = (int) (Math.random() * length);
// 减少的金额根据挑选的值进行变化
double sub = (double) Math.round(Math.random() * 100 * pockets[start]) / 100;
pockets[start] = (double) Math.round((pockets[start] - sub) * 100) / 100;
// 如果减少后的金额少于0.01,那么就不减少,重新挑选值进行分配
if (pockets[start] <= 0.01) {
pockets[start] = (double) Math.round((pockets[start] + sub) * 100) / 100;
continue;
}
pockets[end] = (double) Math.round((pockets[end] + sub) * 100) / 100;
count++;
}
return pockets;
}
public static void main(String[] args) {
RedPocket pocket = new RedPocket();
int money = 100;
int pocketNum = 99;
// 进行计算1000次,根据结果可简单的分析出红包金额的分布范围,最小与最大的红包差会变大,基本符合微信红包的规则
for (int current = 0; current < 1000; current++) {
double[] pockets = pocket.calcuPocket(money, pocketNum);
if (pockets!=null) {
// 进行红包的随机分布
pockets = pocket.changePosition(pockets);
// 获得大概的平均值
double average = (double) Math.round((money / pocketNum) * 100) / 100;
pocket.analysisByMathMethod(current, pockets, average);
}
}
}
}
|