![](/img/trans.png)
[英]Why use i + (int) (Math.random() * (n-i)) instead of (int) (Math.random() * n)?
[英]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
对象。
请注意,随着权重增加,性能会下降。 有一种方法可以使用TreeMap
或binarySearch
进行改进,但是您需要类的实现,以便它可以准备数据。
如果要完全控制随机生成的数字,则应执行以下操作:
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.