微信随机红包(Java)
概述
最近受一朋友提醒,问微信红包怎么实现的,当时思考了一下,觉得好像很容易,可是当真正实现的时候,发现其中有不少问题,于是小白博主查阅资料,其中资料主要来源于知乎的一篇讨论《微信红包的随机算法是怎么样实现的》,这篇文章很好,里面的很多大神给出了不错的思路、算法、乃至代码。
算法
博主的博文主要针对其中的一个算法来实现,算法具体如下:
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)这个方法。
补充
博主水平不高,代码写的也不是很好,代码有什么问题,非常欢迎大家指出,共同学习,共同提高!
微信随机红包(Java)的更多相关文章
- PHP实现微信随机红包算法和微信红包的架构设计简介
微信红包的架构设计简介: 原文:https://www.zybuluo.com/yulin718/note/93148 @来源于QCon某高可用架构群整理,整理朱玉华. 背景:有某个朋友在朋友圈咨询微 ...
- C#开发微信门户及应用(34)--微信裂变红包
在上篇随笔<C#开发微信门户及应用(33)--微信现金红包的封装及使用>介绍了普通现金红包的封装和使用,这种红包只能单独一次发给一个人,用户获取了红包就完成了,如果我们让用户收到红包后,可 ...
- 玩玩微信公众号Java版之七:自定义微信分享
前面已经学会了微信网页授权,现在微信网页的功能也可以开展起来啦! 首先,我们先来学习一下分享,如何在自己的页面获取分享接口及让小伙伴来分享呢? 今天的主人公: 微信 JS-SDK, 对应官方链接为:微 ...
- 微信发红包 PHP 实现
最近做生日营销,需要微信发红包,特此从网上找了一篇教程 首先你的有个服务号,并且开通了微信支付,我在这就不说怎么去申请和开通了,我是看了微信官方文档后,想看官方文档的朋友可以到下面这个链接 https ...
- 微信"流量红包"的玩法攻略 广东移动用户有福啦
前面我们说了广东移动联合微信正式推出流量红包业务,移动终于hold不住了,想要借此挽回一些些损失.只可惜,现在只是广东小范围测试,其他地区的用户暂时还没有这等福利.那么微信"流量红包&quo ...
- 使用nodejs调用微信发送红包
前置条件:申请微信发送红包的账户及其权限 依赖 blueimg-md5和 xmlreader 库 /common/weixin.js 源码 /** * Created by chent696 on 2 ...
- 微信语音红包小程序开发如何提高精准度 红包小程序语音识别精准度 微信小程序红包开发语音红包
公司最近开发的一个微信语音红包,就是前些时间比较火的包你说红包小程序.如何提高识别的精准度呢. 在说精准度之前,先大概说下整个语音识别的开发流程.前面我有文章已经说到过了.具体我就不谈了.一笔带过. ...
- 微信小程序+java后台
博主是大四学生,毕业设计做的是微信小程序+java后台.陆陆续续经历了三个月(因为白天要实习又碰上过年玩了一阵子),从对微信小程序一无所知到完成毕设,碰到许多问题,在跟大家分享一下自己的经历和一个小程 ...
- php 随机红包算法
<?php /** * 红包分配算法 * * example * $coupon = new Coupon(200, 5); * $res = $coupon->handle(); * p ...
随机推荐
- 浏览器加载和渲染HTML的过程(标准定义的过程以及现代浏览器的优化)
先看一下标准定义的浏览器渲染过程(网上找的): 浏览器打开网页的过程 用户第一次访问网址,浏览器向服务器发出请求,服务器返回html文件: 浏览器开始载入html代码,发现 head 标签内有一个 l ...
- Win10 UWP开发系列:实现Master/Detail布局
在开发XX新闻的过程中,UI部分使用了Master/Detail(大纲/细节)布局样式.Win10系统中的邮件App就是这种样式,左侧一个列表,右侧是详情页面.关于这种 样式的说明可参看MSDN文档: ...
- Dapper-据说stackoverflow使用的orm
using System; using System.Collections.Generic; using System.Data; using System.Data.SqlClient; usin ...
- 初识C#接口
C# 接口(Interface) 接口定义了所有类继承接口时应遵循的语法合同.接口定义了语法合同 "是什么" 部分,派生类定义了语法合同 "怎么做" 部分. 接 ...
- SimpleSSO:使用Microsoft.Owin.Security.OAuth搭建OAuth2.0授权服务端
目录 前言 OAuth2.0简介 授权模式 (SimpleSSO示例) 使用Microsoft.Owin.Security.SimpleSSO模拟OpenID认证 通过authorization co ...
- android
配置Activity 的启动模式: 在 AndroidManifest.xml 中配置: <activity android:name=".MainActivity" and ...
- JavaScript的“原型甘露”
今天跟朋友讨论JS的面向对象编程问题,想起了原来曾经看过一篇文章,但是看过很久想不起来了,用了很多关键词,终于用“悟透JavaScript 面向对象”这两个关键词找到了“原文”,原文地址:http: ...
- 对iOS10新增Api的详细探究
本文主要是一些对iOS新功能的探索,之前发现博客里关于iOS新功能的分析大多是过于概括,每个功能几句话,无法了解到具体的功能.所以本次的探索是基于Api层面,着重看一些具体用法所做的笔记,本来想分别画 ...
- Newtonsoft.Json 自定义 解析协议
在开发web api的时候 遇到一个要把string未赋值默认为null的情况改成默认为空字符串的需求 这种情况就需要自定义json序列话的 解析协议了 Newtonsoft.Json默认的解析协议是 ...
- 机器学习实战笔记(Python实现)-03-朴素贝叶斯
--------------------------------------------------------------------------------------- 本系列文章为<机器 ...