概述
经常抢红包会发现,很大的概率是在一开始得时候抢的红包越大,越靠后越小(大概率是这种情况,这是我的经验之谈,也不是一定的)。
对于金额是如何确定的,我们可大概猜测是在用户提交之后就确定的数值,也可以是在用户每次点击的时候触发,确定金额。这两种方式并没有本质的区别。但是对于金额的确定方式,我猜测是用随机数生成的。
大概思路一开始的时候,随机数取值的范围较大,出现大数的可能性更大。越往后可分配金额越少,故而金额越小(不一定,下面的demo也多次出现后面大金额的情况,我都要怀疑我的猜想了)
下面先解释一下生成随机数有两种方式:Math.random()方法和Random类
然后再分析一下抢红包的源码
随机数方法方法
Math.random()方法
该方法默认生成大于等于0.0小于1.0的double型随机数,即0<=Math.random()<=1.0,虽然只能生成0~1之间的数字,但是只要是在后面乘上一个范围值,就可以表示任意范围的数。
(int)(Math.Random()*n) ===>返回大于等于0小于n的随机数
m+(int)(Math.Random()*n) ===>返回大于等于m小于m+n(不包括m+n)的随机数
下面以一个猜数字游戏来举例说明
/**
* 猜数字游戏
*/
import java.util.Scanner;
public class NumGame {
public static void main(String[] args) {
System.out.println("——————猜数字游戏——————\n");
int iNum;
int iGuess;
Scanner in = new Scanner(System.in);// 创建扫描器对象,用于输入
iNum = (int) (Math.random() * 100);// 生成1到100之间的随机数
System.out.print("请输入你猜的数字:");
iGuess = in.nextInt(); // 输入首次猜测的数字
while ((iGuess != -1) && (iGuess != iNum))// 判断输入的数字不是-1或者基准数
{
if (iGuess < iNum)// 若猜测的数字小于基准数,则提示用户输入的数太小,并让用户重新输入
{
System.out.print("太小,请重新输入:");
iGuess = in.nextInt();
} else// 若猜测的数字大于基准数,则提示用户输入的数太大,并让用户重新输入
{
System.out.print("太大,请重新输入:");
iGuess = in.nextInt();
}
}
if (iGuess == -1)// 若最后一次输入的数字是-1,循环结束的原因是用户选择退出游戏
{
System.out.println("退出游戏!");
} else// 若最后一次输入的数字不是-1,用户猜对数字,获得成功,游戏结束
{
System.out.println("恭喜你,你赢了,猜中的数字是:" + iNum);
}
System.out.println("\n———————游戏结束———————");
}
}
Random类
除了Math类中的random方法外,Java中还提供了一种可以获取随机数的方式,那就是Java.util.Random类,该类表示一个随机数生成器,可以通过实例化一个Random对象来创建一个随机数生成器。
这种方式实例化对象时,Java编译器一系统当前时间作为随机数生辰器的种子,因为每时每刻的时间不可能相同,所以生成的随机数将不同,但是如果运行速度太快,也会生成两次运行结果相同的随机数。
同时还提供了各种类型随机数的方法,如下表。
方法 | 返回值 | 功能描述 |
---|---|---|
nextInt() | int | 返回一个随机整数 |
nextInt(int n) | int | 返回一个大于0小于n的随机整数 |
nextLong() | long | 返回一个随机长整型值 |
nextBoolean() | boolean | 返回一个随机布尔型值 |
nextFloat() | float | 返回一个随机浮点型值 |
nextDouble() | double | 返回一个随机双精度型值 |
nextGaussian() | double | 返回一个概率密度为高斯分布的双精度值 |
抢红包!!
import java.text.DecimalFormat;
import java.util.Random;
import java.util.Scanner;
/**
* 模拟微信抢红包功能
*/
public class RedBags { //创建一个RedBags类
public static void main(String[] args) {
System.out.println("—————————模拟微信抢红包—————————\n");
Scanner sc = new Scanner(System.in); //控制台输入
System.out.print("请输入要装入红包的总金额(元):");
double total = sc.nextDouble(); //输入“红包的总金额”
System.out.print("请输入红包的个数(个):");
int bagsnum = sc.nextInt(); //输入“红包的个数”
double min = 0.01; //初始化“红包的最小金额”
Random random = new Random(); //创建随机数对象random
DecimalFormat df = new DecimalFormat("###,###,###.##"); //创建DecimalFormat类的对象df,并设置格式
for (int i = 1; i < bagsnum; i++) { //设置“循环”,边界值是红包数-1
//保证后面至少有(bagsnum - i) 个 最小金额可以发
double safe = (total - (bagsnum - i) * min) / (bagsnum - i); //通过公式模拟数学中的离散模型
double money = (double) random.nextInt((int) ((safe - min) * 100)) / 100 + min; //根据离散模型得到每个红包的金额
total = total - money; //替换total的值
String temp = df.format(money); //调用format()方法,对数字money格式化
System.out.println("第" + i + "个红包:" + temp + "元"); //输出结果
}
String left = df.format(total); //调用format()方法,对数字total格式化
//输出最后一个红包
System.out.println("第" + bagsnum + "个红包:" + left + "元"); //输出结果
sc.close(); //关闭控制台输入
}
}