Java:非均匀分布的随机整数
如何在Java中创建一个随机整数Java:非均匀分布的随机整数,java,random,non-uniform-distribution,Java,Random,Non Uniform Distribution,如何在Java中创建一个随机整数n,介于1和k之间,具有“线性递减分布”,即1最有可能,2不太可能,3不太可能,k最不可能,概率线性递减,如下所示: 我知道关于这个话题已经有几十条线索了,很抱歉,我做了一条新的,但我似乎无法从中创造出我所需要的。我知道使用import java.util.*,代码 Random r=new Random(); int n=r.nextInt(k)+1; 在1和k之间创建一个均匀分布的随机整数 泛化:创建任意分布整数的任何提示,即f(n)=某个函数,p(n)=
n
,介于1
和k
之间,具有“线性递减分布”,即1
最有可能,2
不太可能,3
不太可能,k
最不可能,概率线性递减,如下所示:
我知道关于这个话题已经有几十条线索了,很抱歉,我做了一条新的,但我似乎无法从中创造出我所需要的。我知道使用import java.util.*代码>,代码
Random r=new Random();
int n=r.nextInt(k)+1;
在1
和k
之间创建一个均匀分布的随机整数
泛化:创建任意分布整数的任何提示,即f(n)=某个函数
,p(n)=f(n)/(f(1)+…+f(k))
),也将得到赞赏,例如:
int a = 1; // lower bound, inclusive
int b = k; // upper bound, exclusive
double weightedRand = Math.sqrt(rand.nextDouble()); // use triangular distribution
weightedRand = 1.0 - weightedRand; // invert the distribution (greater density at bottom)
int result = (int) Math.floor((b-a) * weightedRand);
result += a; // offset by lower bound
if(result >= b) result = a; // handle the edge case
.首先想到的解决方案是使用阻塞阵列。每个索引将根据您希望的“可能”程度指定一个值范围。在本例中,您将为1使用更宽的范围,为2使用更小的范围,依此类推,直到k达到一个较小的值(假设为1)
int[]indexBound=newint[k];
int-prevBound=0;
对于(int i=0;i,这应该能满足您的需要:
public static int getLinnearRandomNumber(int maxSize){
//Get a linearly multiplied random number
int randomMultiplier = maxSize * (maxSize + 1) / 2;
Random r=new Random();
int randomInt = r.nextInt(randomMultiplier);
//Linearly iterate through the possible values to find the correct one
int linearRandomNumber = 0;
for(int i=maxSize; randomInt >= 0; i--){
randomInt -= i;
linearRandomNumber++;
}
return linearRandomNumber;
}
此外,以下是从开始索引到停止索引范围内正函数(负函数没有真正意义)的一般解决方案:
public static int getYourPositiveFunctionRandomNumber(int startIndex, int stopIndex) {
//Generate a random number whose value ranges from 0.0 to the sum of the values of yourFunction for all the possible integer return values from startIndex to stopIndex.
double randomMultiplier = 0;
for (int i = startIndex; i <= stopIndex; i++) {
randomMultiplier += yourFunction(i);//yourFunction(startIndex) + yourFunction(startIndex + 1) + .. yourFunction(stopIndex -1) + yourFunction(stopIndex)
}
Random r = new Random();
double randomDouble = r.nextDouble() * randomMultiplier;
//For each possible integer return value, subtract yourFunction value for that possible return value till you get below 0. Once you get below 0, return the current value.
int yourFunctionRandomNumber = startIndex;
randomDouble = randomDouble - yourFunction(yourFunctionRandomNumber);
while (randomDouble >= 0) {
yourFunctionRandomNumber++;
randomDouble = randomDouble - yourFunction(yourFunctionRandomNumber);
}
return yourFunctionRandomNumber;
}
public static int getYourPositiveFunctionRandomNumber(int startIndex,int stopIndex){
//生成一个随机数,其值范围为从startIndex到stopIndex的所有可能整数返回值的0.0到函数值之和。
双随机乘数=0;
对于(int i=startIndex;i=0){
yourFunctionRandomNumber++;
randomDouble=randomDouble-yourFunction(yourFunctionRandomNumber);
}
返回您的函数随机数;
}
注意:对于可能返回负值的函数,一种方法是获取该函数的绝对值,并将其应用于上述每个函数调用的解决方案。有很多方法可以做到这一点,但最简单的方法可能就是生成
两个随机整数,一个在0
和k
之间,称之为x
,一个在0
和h
之间,称之为y
。如果y>mx+b
(m
和b
选择适当…),则
k-x
,elsex
编辑:在这里回复评论,这样我可以有更多的空间
基本上,我的解决方案利用了原始分布中的对称性,其中p(x)
是x
的线性函数。在编辑之前,我回答了关于泛化的问题,这个解决方案在一般情况下不起作用(因为在一般情况下没有这种对称性)
我想象问题是这样的:
您有两个直角三角形,每个kxh
,带有一个公共斜边。组合形状是一个kxh
矩形
生成一个随机点,该点以相等的概率落在矩形内的每个点上
一半时间它会落在一个三角形中,一半时间落在另一个三角形中
假设该点落在较低的三角形中。
- 三角形基本上描述了P.M.F.,三角形在每个x值上的“高度”描述了点具有这样一个x值的概率。(记住,我们只处理下三角形中的点。)因此,通过产生x值
假设该点落在上三角形中。
- 反转坐标,并使用下面的三角形如上所述进行处理
您还必须处理边缘情况(我没有麻烦)。例如,我现在看到您的分布从1开始,而不是0,因此其中有一个off by 1,但它很容易修复。最简单的方法是生成一个列表或数组,其中包含权重中所有可能的值
int k = /* possible values */
int[] results = new int[k*(k+1)/2];
for(int i=1,r=0;i<=k;i++)
for(int j=0;j<=k-i;j++)
results[r++] = i;
// k=4 => { 1,1,1,1,2,2,2,3,3,4 }
// to get a value with a given distribution.
int n = results[random.nextInt(results.length)];
int k=/*可能的值*/
int[]结果=新的int[k*(k+1)/2];
对于(int i=1,r=0;i如果你的分布是这样的,你可以计算它的累积分布函数(cdf),那么没有必要用数组来模拟它。上面你有一个概率分布函数(pdf).h实际上是确定的,因为曲线下的面积必须是1。为了简化数学,让我假设你在[0,k]中选取了一个数字
如果我没看错的话,这里的pdf是f(x)=(2/k)*(1-x/k)。cdf只是pdf的积分。这里,这是f(x)=(2/k)*(x-x^2/2k)。(你可以对任何pdf函数重复这个逻辑,如果它是可积的。)
然后你需要计算cdf函数的倒数,F^-1(x),如果我不懒惰,我会帮你做的
但好消息是:一旦你有了F^-1(x),你所要做的就是将它应用于[0,1]中均匀分布的随机值并对其应用函数。java.util.Random可以提供一些注意。这是您分布中的随机采样值。受rlibby启发,让我尝试另一个答案。这个特定分布也是从相同范围内均匀随机选择的两个值中较小值的分布。因此我们需要以下分布,从最不可能到最可能:
*
**
***
****
*****
等等
让我们尝试将均匀分布的整数随机变量映射到该分布:
1
2 3
4 5 6
7 8 9 10
11 12 13 14 15
等等
这样,如果我们为K=5
生成一个从1到15的均匀分布的随机整数,我们只需要找出它适合哪个桶。棘手的部分是如何做到这一点
请注意,右边的数字是三角形数字!这意味着对于从1
到T\u n
随机生成的X
,我们只需要找到n
,这样T\u(n-1)<
1
2 3
4 5 6
7 8 9 10
11 12 13 14 15
// Assume k is given, via parameter or otherwise
int k;
// Assume also that r has already been initialized as a valid Random instance
Random r = new Random();
// First, generate a number from 1 to T_k
int triangularK = k * (k + 1) / 2;
int x = r.nextInt(triangularK) + 1;
// Next, figure out which bucket x fits into, bounded by
// triangular numbers by taking the triangular root
// We're dealing strictly with positive integers, so we can
// safely ignore the - part of the +/- in the triangular root equation
double triangularRoot = (Math.sqrt(8 * x + 1) - 1) / 2;
int bucket = (int) Math.ceil(triangularRoot);
// Buckets start at 1 as the least likely; we want k to be the least likely
int n = k - bucket + 1;
class DiscreteDistribution
{
// cumulative distribution
final private double[] cdf;
final private int k;
public DiscreteDistribution(Function<Integer, Double> pdf, int k)
{
this.k = k;
this.cdf = new double[k];
double S = 0;
for (int i = 0; i < k; ++i)
{
double p = pdf.apply(i+1);
S += p;
this.cdf[i] = S;
}
for (int i = 0; i < k; ++i)
{
this.cdf[i] /= S;
}
}
/**
* transform a cumulative distribution between 0 (inclusive) and 1 (exclusive)
* to an integer between 1 and k.
*/
public int transform(double q)
{
// exercise for the reader:
// binary search on cdf for the lowest index i where q < cdf[i]
// return this number + 1 (to get into a 1-based index.
// If q >= 1, return k.
}
}
int a = 1; // lower bound, inclusive
int b = k; // upper bound, exclusive
double weightedRand = Math.sqrt(rand.nextDouble()); // use triangular distribution
weightedRand = 1.0 - weightedRand; // invert the distribution (greater density at bottom)
int result = (int) Math.floor((b-a) * weightedRand);
result += a; // offset by lower bound
if(result >= b) result = a; // handle the edge case