zoukankan      html  css  js  c++  java
  • JAVA实现概率计算(数字不同范围按照不同几率产生随机数)

    程序中经常遇到随机送红包之类的情景,这个随机还得指定概率,比如10%的机率可以得到红包。那么java怎么实现一个简单的概率计算了,见如下例子:

    int randomInt =  RandomUtils.nextInt(1,101);
    if(randomInt <= 10){ //100里面1个数,小于等于10的概率就是10%
           //do something
    }

    RandomUtils工具类是commons-lang3包里面的

    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.7</version>
    </dependency>

     如果要在某个数字区间产生一个随机数,区间内部在不同的片段几率不同如何实现呢?经常有这样的场景,比如,随机赠送红包,范围0.1元-100元,0.1-1元的概率是90%,1元-10元的概率是9%,10元-100元的概率是1%,也就是说数额越大得到的几率越小!实现的原理如下图:

    原理就是,将范围分割成一个个子范围(片段),具体采用哪个范围,再用机率判断。片段机率可以依次排好序,映射成[1,100]之间的数字。然后随机一个[1,100]之间的数,该数落在哪个区间,就采用哪个片段产生随机数。具体源代码如下:

    package com.hdwang;
    
    import org.apache.commons.lang3.RandomUtils;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 按几率产生随机数
     * 例如,产生0.1-100的随机数,0.1-1的几率是90%,1-10的几率是9%,10-100的几率是1%
     */
    public class RateRandomNumber {
    
        /**
         * 产生随机数
         * @param min 最小值
         * @param max 最大值
         * @return 随机结果
         */
        public static double produceRandomNumber(double min,double max){
            return RandomUtils.nextDouble(min,max); //[min,max]
        }
    
        /**
         * 按比率产生随机数
         * @param min 最小值
         * @param max 最大值
         * @param separates 分割值(中间插入数)
         * @param percents 每段数值的占比(几率)
         * @return 按比率随机结果
         */
        public static double produceRateRandomNumber(double min,double max,List<Double> separates,List<Integer> percents){
            if(min > max){
                throw new IllegalArgumentException("min值必须小于max值");
            }
            if(separates == null || percents==null || separates.size()==0){
                return produceRandomNumber(min,max);
            }
            if(separates.size() +1 != percents.size()){
                throw new IllegalArgumentException("分割数字的个数加1必须等于百分比个数");
            }
            int totalPercent = 0;
            for(Integer p:percents){
                if(p<0 || p>100){
                    throw  new IllegalArgumentException("百分比必须在[0,100]之间");
                }
                totalPercent += p;
            }
            if(totalPercent != 100){
                throw new IllegalArgumentException("百分比之和必须为100");
            }
            for(double s:separates){
                if(s <= min || s >= max){
                    throw new IllegalArgumentException("分割数值必须在(min,max)之间");
                }
            }
            int rangeCount = separates.size()+1; //例如:3个插值,可以将一个数值范围分割成4段
            //构造分割的n段范围
            List<Range> ranges = new ArrayList<Range>();
            int scopeMax = 0;
            for(int i=0;i<rangeCount;i++){
                Range range = new Range();
                range.min = (i==0 ? min:separates.get(i-1));
                range.max = (i== rangeCount-1 ?max:separates.get(i));
                range.percent = percents.get(i);
    
                //片段占比,转换为[1,100]区间的数字
                range.percentScopeMin = scopeMax +1;
                range.percentScopeMax = range.percentScopeMin + (range.percent-1);
                scopeMax = range.percentScopeMax;
    
                ranges.add(range);
            }
            //结果赋初值
            double r = min;
            int randomInt = RandomUtils.nextInt(1,101); //[1,100]
            for(int i=0;i<ranges.size();i++){
                Range range = ranges.get(i);
                //判断使用哪个range产生最终的随机数
                if(range.percentScopeMin <= randomInt && randomInt <= range.percentScopeMax){
                    r = produceRandomNumber(range.min,range.max);
                    break;
                }
            }
            return r;
        }
    
        public static class Range{
            public double min;
            public double max;
            public int percent; //百分比
    
            public int percentScopeMin; //百分比转换为[1,100]的数字的最小值
            public int percentScopeMax; //百分比转换为[1,100]的数字的最大值
        }
    
        public static void main(String[] args) {
            List<Double> separates = new ArrayList<Double>();
            separates.add(1.0);
            separates.add(10.0);
            List<Integer> percents = new ArrayList<Integer>();
            percents.add(90);
            percents.add(9);
            percents.add(1);
            for(int i=0;i<100;i++) {
                double number = produceRateRandomNumber(0.1, 100, separates, percents);
                System.out.println(String.format("%.2f",number));
            }
        }
    }
  • 相关阅读:
    Java面试题(转)
    哪种方式更适合在React中获取数据?
    vue学习之深入响应式原理
    还不会用FindBugs?你的代码质量很可能令人堪忧
    几道大数据面试题(转)
    【Medium翻译】Java抽象类有什么用?
    深入理解Kafka必知必会(上)
    (八十六)c#Winform自定义控件-表格优化(转载)
    IDEA 配置及常用快捷键
    Markdown 复杂公式&常用符号
  • 原文地址:https://www.cnblogs.com/hdwang/p/9172172.html
Copyright © 2011-2022 走看看