首页 技术 正文
技术 2022年11月8日
0 收藏 633 点赞 1,468 浏览 3208 个字

概述

  最近受一朋友提醒,问微信红包怎么实现的,当时思考了一下,觉得好像很容易,可是当真正实现的时候,发现其中有不少问题,于是小白博主查阅资料,其中资料主要来源于知乎的一篇讨论《微信红包的随机算法是怎么样实现的》,这篇文章很好,里面的很多大神给出了不错的思路、算法、乃至代码。

算法

  博主的博文主要针对其中的一个算法来实现,算法具体如下:

  1.确定红包总额(M)、发放人数(n),计算可分配金额(A),A = M – n * 0.01,若A < 0,则转至步骤②,否则进入步骤③;

  2.输入有误,重新输入红包总额和发放人数,转至步骤①;

  3.生成一个n个元素的数组money_rand[n],其中每个元素随即为0 – 99之间,并计算出总和money_rand_total = money_rand[0] + money_rand[1] + … money_rand[n -1];

  4.每个人红包抢到的钱数:money_get[i] = money_rand[i] / money_rand_total + 0.01;

实现前需要了解的问题

  1.在Java中,对于小数的计算,如果位数较多,建议使用BigDecimal类来处理,至于原因,是Java语言在表示小数的时候存在误差,即0.1≠0.1的奇怪的现象,具体原因,这篇CSDN的文章解释的很好:java用double和float进行小数计算精度不准确

  2.由于是金钱敏感的程序,所以务必在完成程序后进行测试,确保不要出现金钱为负值或者0,或者总和超过发放金额的情况,博主已将本代码简单测试过了,基本没问题。

完整代码实现(Java)

 import java.math.BigDecimal; import java.util.Random; public class WeChatMoney {     private static final int DEF_DIV_SCALE=10;     /**      * @param args      */     public static void main(String[] args) {         double total_money = 100;         int person_num = 10;         double[] arr = new double[person_num];         arr = GetWechat(total_money, person_num);         for(double it:arr){                 System.out.println(it);         }         System.out.println("end");     }     /**      * 用户获得一个double型数组,数组大小为红包人数,数组元素值为每个人分配到总额的随即的值      * @param total_money 红包总额      * @param person_num 人数      * @return double型数组      */     private static double[] GetWechat(double total_money, int person_num) {         double[] money_arr = new double[person_num];         //为了确保安全,先从金钱总额减去0.01 * 人数,以确保最低的人可以获得0.01元         double left_allocate_money = sub(total_money, person_num * 0.01);         if(left_allocate_money < 0){             System.out.println("请重新输入红包金额和红包数量");         }else{             double already_all = 0;             int random_num_total = 0;             int[] random_rate_num = new int[person_num];             Random r = new Random();             /*用于初始化随机数数组:x1,x2,x3,x4,x5...             并计算出随机数组总和:random_num_total = x1+x2+x3+...+xn*/             for(int i = 0; i< person_num; i++){                 random_rate_num[i] = r.nextInt(100);                 random_num_total += random_rate_num[i];             }             for(int i = 0;i < person_num; i++){                 /*若不是最后一个,则计算公式如下:                   money = rand(i) / (rand(1) + rand(2) + ... + rand(n)),                       (其中,保留两位小数采用乘100取整后,再除以100)                       若是最后一个,则那剩余金额 = 可分配金额减去已分配金额*/                 if(i != person_num -1){                     BigDecimal bg = new BigDecimal(div(mul(random_rate_num[i], left_allocate_money), random_num_total));                     money_arr[i] = bg.setScale(2, BigDecimal.ROUND_FLOOR).doubleValue();                     already_all = add(already_all, money_arr[i]);                 }else{                     money_arr[i] = sub(left_allocate_money, already_all);                 }                 //最终加上0.01元,保证不会出现0元的情况                 money_arr[i] = add(money_arr[i], 0.01);             }         }         return money_arr;     }     //相加     public static double add(double d1,double d2){         BigDecimal b1=new BigDecimal(Double.toString(d1));         BigDecimal b2=new BigDecimal(Double.toString(d2));         return b1.add(b2).doubleValue();     }     //相减     public static double sub(double d1,double d2){         BigDecimal b1=new BigDecimal(Double.toString(d1));         BigDecimal b2=new BigDecimal(Double.toString(d2));         return b1.subtract(b2).doubleValue();     }     //相乘     public static double mul(double d1,double d2){         BigDecimal b1=new BigDecimal(Double.toString(d1));         BigDecimal b2=new BigDecimal(Double.toString(d2));         return b1.multiply(b2).doubleValue();     }     //相除     public static double div(double d1,double d2){         return div(d1,d2,DEF_DIV_SCALE);     }     public static double div(double d1,double d2,int scale){         if(scale<0){             throw new IllegalArgumentException("The scale must be a positive integer or zero");         }         BigDecimal b1=new BigDecimal(Double.toString(d1));         BigDecimal b2=new BigDecimal(Double.toString(d2));         return b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();     } }

  其中为了减少代码冗余,直接将BigDecimal的计算封装在函数内,本质上,从算法理解只有GetWechat(double, int)这个方法。

补充

  博主水平不高,代码写的也不是很好,代码有什么问题,非常欢迎大家指出,共同学习,共同提高!

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,492
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,907
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,740
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,494
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:8,132
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:5,295