如何创建不均匀的范围数随机函数?

我们知道经典范围随机函数是这样的:

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%部分)。

使用上面的算法:

 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); } 

您可以使用所需的密度填充所需数字的数组,然后生成随机索引并获取相应的元素。 我觉得它有点快,但可能它并不那么重要。 这样的事情,这不是正确的解决方案,只是一个例子:

 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); 

滚动72面模具以从以下arrays中进行选择:

 // 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] 
 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)]; 

或类似的规定…

如果您使用整数,这可能会有所帮助:

您需要使用以下function:

 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倍,其值从随机数生成器均匀分布。 这同样适用于第3分支。

我希望这有帮助!

编辑:修改间隔,你必须稍微调整一下,但这是我的一般想法。

根据要求,这是我的代码(基于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 

用法示例:

 int result = weightedRangeRandom(1, 10, new float[] {0.3f, 0.4f, 0.3f}, new float[] {1f/2, 1f/6, 1f/3}); 

由于按重量划分导致十进制值,代码在分配子范围边界(tMin和tMax)时可能仍然存在不准确性。 但我想这是不可避免的,因为范围数是整数。

可能需要一些输入validation,但为了简单起见,我遗漏了。

非常欢迎评论家,更正和评论:)