我们知道,经典的范围内随机函数是这样的:
public static final int random(final int min, final int max) {
Random rand = new Random();
return min + rand.nextInt(max - min + 1); // +1 for including the max
}
我想创建算法函数在1..10之间范围内随机生成的数字,但带状凹凸的可能性:
1)1,2,3 - > 3/6(1/2)
2)4,5,6,7- - > 1/6
3)8,9,10 - > 2/6(1/3)
以上意味着函数具有1/2的机会1和3之间返回数,1/6的机会至4和7之间返回数,和1/3的机会至8和10之间返回数量。
任何人都知道的算法?
更新:
其实1..10之间的范围只是担任一个例子。 我想创建的功能将适用于数字,如任何范围:1..10000,但规则还是一样的:3/6的顶部范围(30%部分),为1/6中间范围(下一40%的部分),和2/6为底的范围(近30%的部分)。
Answer 1:
使用上面的算法:
int temp = random(0,5);
if (temp <= 2) {
return random(1,3);
} else if (temp <= 3) {
return random(4,7);
} else {
return random(8,10);
}
这应该做的伎俩。
编辑:根据要求在您的评论:
int first_lo = 1, first_hi = 3000; // 1/2 chance to choose a number in [first_lo, first_hi]
int second_lo = 3001, second_hi = 7000; // 1/6 chance to choose a number in [second_lo, second_hi]
int third_lo = 7001, third_hi = 10000;// 1/3 chance to choose a number in [third_lo, third_hi]
int second
int temp = random(0,5);
if (temp <= 2) {
return random(first_lo,first_hi);
} else if (temp <= 3) {
return random(second_lo,second_hi);
} else {
return random(third_lo,third_hi);
}
Answer 2:
可以填充所期望的密度所需的数字阵列,然后生成随机索引,并采取相应的元素。 我认为这是快了一点,但propably它不是那么重要。 类似的东西,这不是正确的解决方案,只是一个例子:
1,1,1,2,2,2,3,3,3,4,5,6 ...
或者你可以用if语句首先定义域,然后生成该域中一个简单的数字。
int x = random(1,6)
if (x < 4) return random(1, 3);
if (x < 5) return random(4, 7);
return random(8, 10);
Answer 3:
滚72面的骰子从下面的阵列中选择:
// Each row represents 1/6 of the space
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7,
8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9,
9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10]
Answer 4:
final int lut[] = [
1, 1, 1,
2, 2, 2,
3, 3, 3,
4,
5,
6,
7,
8, 8,
9, 9,
10, 10
];
int uneven_random = lut[random.nextInt(lut.length)];
或类似的规定...
Answer 5:
这可能,如果你使用的整数帮助:
您需要使用以下功能:
f : A -> B
B = [B0,B1]表示您从随机数发生器希望值的范围
A = [B0,2 * B1],使得F的实际到达B1的最后一个分支
f(x) = step((x / 3) ,
f(x) is part of interval [b0, length(B)/3]
f(x) = step(x) + E,
f(x) is part of interval [length(B) / 3, 2 * length(B) / 3],
E is a constant that makes sure the function is continuous
f(x) = step(x / 2) + F,
f(x) is part of interval [2 * length(B) / 3, length(B)]
F is a constant that makes sure the function is continuous
说明:这将需要3倍以上的数字得到比它会在第二第一分支相同的值。 所以概率获得第一分支数量比第二的3倍,其值从平均随机数发生器分布。 这同样适用于第三分公司。
我希望这有帮助!
编辑:修改时间间隔,你必须调整它有点,但是这是我的总体思路。
Answer 6:
按照要求,这里是我的代码(基于izomorphius的代码),希望能解决我的问题:
private static Random rand = new Random();
public static int rangeRandom(final int min, final int max) {
return min + rand.nextInt(max - min + 1); // +1 for including the max
}
/**
*
* @param min The minimum range number
* @param max The maximum range number
* @param weights Array containing distributed weight values. The sum of values must be 1.0
* @param chances Array containing distributed chance values. The array length must be same with weights and the sum of values must be 1.0
* @return Random number
* @throws Exception Probably should create own exception, but I use default Exception for simplicity
*/
public static int weightedRangeRandom(final int min, final int max, final float[] weights, final float[] chances) throws Exception {
// some validations
if (weights.length != chances.length) {
throw new Exception("Length of weight & chance must be equal");
}
int len = weights.length;
float sumWeight = 0, sumChance = 0;
for (int i=0; i<len; ++i) {
sumWeight += weights[i];
sumChance += chances[i];
}
if (sumWeight != 1.0 || sumChance != 1.0) {
throw new Exception("Sum of weight/chance must be 1.0");
}
// find the random number
int tMin = min, tMax;
int rangeLen = max - min + 1;
double n = Math.random();
float c = 0;
for (int i=0; i<len; ++i) {
if (i != (len-1)) {
tMax = tMin + Math.round(weights[i] * rangeLen) - 1;
}
else {
tMax = max;
}
c += chances[i];
if (n < c) {
return rangeRandom(tMin, tMax);
}
tMin = tMax + 1;
}
throw new Exception("You shouldn't end up here, something got to be wrong!");
}
用法示例:
int result = weightedRangeRandom(1, 10, new float[] {0.3f, 0.4f, 0.3f},
new float[] {1f/2, 1f/6, 1f/3});
可能仍然具有重量分布由于分立的子范围的边界(TMIN&TMAX)的不准确度的代码导致十进制值。 但它是不可避免的我猜的,因为范围内的数字为整数。
一些输入验证可能是必需的,但我离开了为简单起见。
批评,更正和评论深表欢迎:)
文章来源: How to create uneven range number random function?