![](/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.