繁体   English   中英

嗨,我想使用math.random设置重复的可能性

[英]Hi I want to use math.random to set the likely for it to repeat

我想制作一个将生成随机数的程序。 我知道我需要为此使用Math.random(),但我想为可重复的数字设置比率。 例如,我希望编译器给出一个从1到10的数字,但我希望5重复一个比另一个数字大3倍的数字。 我怎么做? 请帮忙谢谢。

对于这种情况:

private static final int[] CHOICES = new int[] { 1, 2, 3, 4, 5, 5, 5, 6, 7, 8, 9, 10 };
public static int strangeRandom() {
    return CHOICES[ThreadLocalRandom.current().nextInt(CHOICES.length)];
}

从给定的一组选择中随机选择,然后控制这些选择,以便更有可能选择5种。

这将使5个数字至少是其他9个数字的3倍:

private static int getRandom ()
{
    Random r = new Random();

    int next = r.nextInt(100000) + 1;

    if (next <= 25000)
    {
        return 5;
    }
    else
    {
        return r.nextInt(10) + 1;
    }
}

注意 :在其他情况下,也可以排除5,以尝试更好地达到“ 3次”的可能性。 我不是为了简单。

另一个变化 :这是一个使用nextInt()模数而不是25000/100000分割的变化。 另外,我将代码放在其他情况下,尝试排除5(没有无限循环)。

private static int getRandom ()
{
    Random r = new Random();

    int next = r.nextInt();

    if (next % 4 == 0)
    {
        return 5;
    }
    else
    {
        int p = r.nextInt(10) + 1;
        int tries = 0;

        // try to not get a 5 for a few times
        while (p == 5 && tries++ < 4)
        {
            p = r.nextInt(10) + 1;
        }
        return p;
    }
}

测试代码

public static void main(String[] args)
{       
    Map<Integer, Integer> frequecnyMap = new HashMap<Integer, Integer>();

    for (int i = 0; i < 12000; i++)
    {
        int r = getRandom();

        Integer n = frequecnyMap.get(r);

        if (n == null)
        {
            frequecnyMap.put(r, 1);
        }
        else
        {
            frequecnyMap.put(r, n + 1);
        }
    }
    System.out.println(frequecnyMap);
}

样本输出(第二变化)

{1 = 971,2 = 975,3 = 995,4 = 1037,5 = 3025,6 = 1042,7 = 995,8 = 976,9 = 969,10 = 1015}

{1 = 1016、2 = 1019、3 = 994、4 = 968、5 = 3068、6 = 1030、7 = 996、8 = 914、9 = 990、10 = 1005}

{1 = 939,2 = 944,3 = 979,4 = 986,5 = 3023,6 = 1040,7 = 1007,8 = 1046,9 = 997,10 = 1039}

首先,您应该使用Random类,而不是Math.random() 例如,它具有一个不错的辅助方法nextInt(int n) ,该方法生成介于0和n-1(含)之间的随机整数。

在您的特定情况下,您需要一个1-10的数字,因此生成0-9并加1,即nextInt(10) + 1

但是,您希望数字5出现3次的频率更高。 一种快速的肮脏方法是生成两个额外的数字(1-12)并将它们映射到5。

Random rnd = new Random();
int num = rnd.nextInt(12) + 1;
if (num == 11 || num == 12)
    num = 5;

就像我说的那样,既快捷又肮脏,但这确实适合您的特定情况。


现在,对于更通用的解决方案,您希望能够指定加权概率。 数字1-4、6-10的权重为1,数字5的权重为3。

然后,您要做的是对权重求和(12),并生成一个随机数,然后找到累加权重超过该随机数的数字。

这是一种方法:

private static int random(Random rnd, int ... weights) {
    if (weights.length < 2)
        throw new IllegalArgumentException("Need at least two weights");
    int total = 0;
    for (int weight : weights) {
        if (weight <= 0)
            throw new IllegalArgumentException("Invalid weight: " + weight);
        if ((total += weight) < 0)
            throw new IllegalArgumentException("Weight overflow");
    }
    for (int i = 0, val = rnd.nextInt(total); ; i++, val -= weights[i])
        if (val < weights[i])
            return i;
}

然后可以这样称呼它:

Random rnd = new Random();
int num = random(rnd, 1,1,1,1,3,1,1,1,1,1) + 1;

注意+1 ,因为该方法类似于Random.nextInt(n)并且将数字0返回到n-1,其中n是给定的权重数。

您可以轻松地将其变成一个不错的类,在该类上权重由构造函数指定,并且该类为您管理Random对象。

请注意,随着权重增加,性能会下降。 有一种方法可以使用TreeMapbinarySearch进行改进,但是您需要类的实现,以便它可以准备数据。

如果要完全控制随机生成的数字,则应执行以下操作:

public class MyRandom {
    private int[] probability;
    private long[] ntimes;
    private long times;

    public MyRandom(int[] probability) {
        this.probability = new int[10];
        System.arraycopy(probability, 0, this.probability, 0, probability.length);
        ntimes=new long[10];
        for(int i=0; i < ntimes.length; i++)
            ntimes[i]=0;
        times=0;
    }

    public void showProbability() {
        for (long i : probability) {
            System.out.print(i+" ");
        }
        System.out.println();
    }

    public int random() {
        int t = 10;

        int r = (int)Math.floor(Math.random()*10+1);
        double p = 0;
        if (times == 0) 
            p = 0;
        else
            p = ntimes[r-1]*100/times;

        System.out.println("P: "+p +" : "+probability[r-1]);
        while (p > probability[r-1] && t > 0) {
            r = (int)Math.floor(Math.random()*10+1);
            p = ntimes[r-1]*100/times;            
            t--;
        }
        ntimes[r-1]++;
        times++;
        return r;
    }

    public long getOcurrences(int i) {
        return ntimes[i-1];
    }


    //This is an example of how to use it.        
    public static void main(String[] args) {
        int[] p = {5, 5, 5, 5, 30, 5, 5, 5, 10, 15};
        MyRandom mr = new MyRandom(p);

        for (int i = 0; i < 2000; i++) {
            int r = mr.random();
            System.out.println("Id: "+i+" Number: "+r+" Ocurrences: "+mr.getOcurrences(r));
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM