三角数组中的Java偏置随机数

三角数组中的Java偏置随机数,java,math,random,probability,Java,Math,Random,Probability,这个问题是问题的延伸。我随机选择了两个数字(包括0-12),我希望这些值相等 但现在,由于这是一个乘法游戏,我想找到一种方法来偏向结果,以便某些组合出现得更频繁(比如如果玩家在12x8上表现更差,我希望它出现得更频繁)。最后,我想偏向91种组合中的任何一种,但一旦我把这一点记下来,那就不难了 我的想法是:将一些int n添加到三角形数字中,然后Random.nextInt(91+n)将结果偏向于一个组合 private int[] triLessThan(int x, int[] bias) {

这个问题是问题的延伸。我随机选择了两个数字(包括0-12),我希望这些值相等

但现在,由于这是一个乘法游戏,我想找到一种方法来偏向结果,以便某些组合出现得更频繁(比如如果玩家在12x8上表现更差,我希望它出现得更频繁)。最后,我想偏向91种组合中的任何一种,但一旦我把这一点记下来,那就不难了

我的想法是:将一些
int n
添加到三角形数字中,然后
Random.nextInt(91+n)
将结果偏向于一个组合

private int[] triLessThan(int x, int[] bias) { // I'm thinking a 91 element array, 0 for no bias, positive for bias towards
    int i = 0;
    int last = 0;
    while (true) {
                    int sum = 0;
                    for (int a = 0; a < i * (i + 2)/2; a++){
                        sum += bias[a]
                    }
        int triangle = i * (i + 1) / 2;
        if (triangle + sum > x){
            int[] toReturn = {last,i};
            return toReturn;
        }
        last = triangle;
        i++;
    }
}
sumOfArray只找到和(这个公式很简单)。这样行吗

编辑:使用Floris的想法:

随机数字滚动:

int[] bias = {1,1,1,...,1,1,1} // 91 elements
int roll = random.nextInt(sumOfBias());
int num1 = roll;
int num2 = 0;
while (roll > 0){
    roll -= bias[num2];
    num2++;
}
num1 = (int) (Math.sqrt(8 * num2 + 1) - 1)/2;
num2 -= num1 * (num1 + 1) / 2;

你已经知道如何将一个介于0和91之间的数字转换成一个滚动(从上一个问题的答案开始)。我建议您创建一个由N个元素组成的数组,其中N>>91。用0…90填充前91个元素,并将计数器
a
设置为91。现在选择一个介于0和a之间的数字,从数组中选择相应的元素,并转换为乘法问题。如果答案是错误的,则将问题编号附加到数组末尾,并将
A
增加1

这将创建一个数组,在该数组中,采样频率将表示错误解决问题的次数,但如果下次问题得到正确解决,则不会再次降低频率

另一种更好的解决方案,与您的解决方案更接近(但不同),它创建了一个91个频率的数组,每个频率最初设置为1,并跟踪总和(最初为91)。但是现在,当您选择一个随机数(介于0和sum之间)时,您将遍历数组,直到累积和大于您的随机数-箱子的数量是您选择的滚动,并使用前面导出的公式进行转换。如果答案是错误的,则增加bin并更新总和;如果正确,则将总和递减,但决不使其值小于1,然后更新总和。重复一遍

这应该给你你想要的东西:给定一个91个数字的数组(“箱子”),随机选择一个箱子,这样箱子的概率与里面的值成正比。返回bin的索引(可以使用以前的方法将其转换为数字的组合)。调用此函数时,bin(frequency)数组作为第一个参数,累积和作为第二个参数。查找前n个元素的累积和首先超过由频率之和缩放的随机数的位置:

private int chooseBin(float[] freq, float fsum) {
// given an array of frequencies (probabilities) freq
// and the sum of this array, fsum
// choose a random number between 0 and 90
// such that if this function is called many times
// the frequency with which each value is observed converges
// on the frequencies in freq
    float x, cs=0; // x stores random value, cs is cumulative sum
    int ii=-1;     // variable that increments until random value is found

    x = Math.rand();

    while(cs < x*fsum && ii<90) { 
    // increment cumulative sum until it's bigger than fraction x of sum
        ii++;
        cs += freq[ii];
    }
return ii;
}
当您使
a
接近1时,函数倾向于使用较小的数字,而较大数字的概率几乎为零:

我相信以下代码部分与我描述的一样:

private int[] chooseProblem(float bias, int[] currentShuffle) { 
// if bias == 0, we choose from uniform distribution
// for 0 < bias <= 1, we choose from increasingly biased distribution
// for bias > 1, we choose from uniform distribution
// array currentShuffle contains the numbers 0..90, initially in shuffled order
// when a problem is solved correctly it is moved to the top of the pile
// when it is wrong, it is moved to the bottom.
// return value contains number1, number2, and the current position of the problem in the list
    int problem, problemIndex;

    if(bias < 0 || bias > 1) bias = 0;

    if(bias == 0) {
        problem = random.nextInt(91);
        problemIndex = problem;
    }
    else {
        float x = asin(Math.random()*bias)/asin(bias);
        problemIndex = Math.floor(91*x);
        problem = currentShuffle[problemIndex];
    }

    // now convert "problem number" into two numbers:
    int first, last;    
    first = (int)((Math.sqrt(8*problem + 1)-1)/2);
    last = problem - first * (first+1) / 2;

    // and return the result:
    return {first, last, problemIndex};
}


private void shuffleProblems(int[] currentShuffle, int upDown) {
// when upDown==0, return a randomly shuffled array
// when upDown < 0, (wrong answer) move element[-upDown] to zero
// when upDown > 0, (correct answer) move element[upDown] to last position
// note - if problem 0 is answered incorrectly, don't call this routine!

    int ii, temp, swap;

    if(upDown == 0) {

        // first an ordered list:
        for(ii=0;ii<91;ii++) {
            currentShuffle[ii]=ii;
        }

        // now shuffle it:
        for(ii=0;ii<91;ii++) {
            temp = currentShuffle[ii];
            swap = ii + random.nextInt(91-ii);
            currentShuffle[ii]=currentShuffle[swap];
            currentShuffle[swap]=temp;
        }
        return;
    }

    if(upDown < 0) {
        temp = currentShuffle[-upDown];
        for(ii = -upDown; ii>0; ii--) {
            currentShuffle[ii]=currentShuffle[ii-1];
        }
        currentShuffle[0] = temp;
    }
    else {
        temp = currentShuffle[upDown];
        for(ii = upDown; ii<90; ii++) { 
            currentShuffle[ii]=currentShuffle[ii+1];
        }
        currentShuffle[90] = temp;
    }
    return;
}


// main problem posing loop:

int[] currentShuffle = new int[91];
int[] newProblem;
int keepGoing = 1;

// initial shuffle:
shuffleProblems( currentShuffle, 0); // initial shuffle

while(keepGoing) {
    newProblem = chooseProblem(bias, currentShuffle);
    // pose the problem, get the answer
    if(wrong) {
        if(newProblem > 0) shuffleProblems( currentShuffle, -newProblem[2]);
    }
    else shuffleProblems( currentShuffle, newProblem[2]);
    // decide if you keep going...
}
private int[]选择问题(float bias,int[]currentShuffle){
//如果偏差=0,我们从均匀分布中选择
//对于0<偏差1,我们选择均匀分布
//数组currentsuffle包含数字0..90,最初按无序顺序排列
//当问题得到正确解决时,它将移动到桩的顶部
//当它出错时,会移到底部。
//返回值包含number1、number2和列表中问题的当前位置
int问题,problemIndex;
如果(偏差<0 | |偏差>1)偏差=0;
如果(偏差==0){
问题=随机。nextInt(91);
问题指数=问题;
}
否则{
float x=asin(数学随机()*偏差)/asin(偏差);
problemIndex=数学楼层(91*x);
problem=currentShuffle[problemIndex];
}
//现在将“问题编号”转换为两个编号:
int首先,最后;
第一个=(int)((数学sqrt(8*问题+1)-1)/2);
最后一个=问题-第一个*(第一个+1)/2;
//并返回结果:
返回{first,last,problemIndex};
}
私有无效shuffleProblems(int[]currentShuffle,int upDown){
//当upDown==0时,返回一个随机排列的数组
//当upDown<0时,(回答错误)将元素[-upDown]移动到零
//当upDown>0时,(回答正确)将元素[upDown]移动到最后一个位置
//注意-如果问题0回答不正确,请不要调用此例程!
内部ii、临时、交换;
如果(向上向下==0){
//首先是有序列表:

对于(ii=0;ii为什么你不亲自尝试并验证它是否有效?(O_O)@好吧,我问了一个问题并提出了一个可能的解决方案。如果它有效,那么你只需将其作为答案发布,你就会被接受。我想我明白了你的意思;我用我认为你推荐的代码对你的帖子进行了编辑。但是,我认为应该是
int num2=rollStore(int)(Math.sqrt(8*num1+1)-1)/2
。以下是我理解的:
int[]bias={1,1,…,1,1};//91个元素
roll=random.nextInt(sumobias());
int num1=0
for(;roll>0;num1++)roll-=bias[num1]
(在编辑过程中犯了一些错误。)还有几件事:为了偏移某个数字,我可以增加数组中的每一个元素。rollStore是不必要的;我可以在创建rollStore的地方,使num2等于roll,然后执行
num2-=(int)(Math.sqrt(8*num1+1)-1)/2、 
很抱歉-我似乎与您同时编辑代码,而我的编辑在某种程度上超过了您的编辑…我将添加一些代码来展示最后一个示例(我认为是最好的示例)是如何编写的会有用的。看起来太复杂了…我将对我的帖子进行另一次编辑,以显示我从你的原始帖子中得到的信息。我认为会的-你基本上做了与我当前答案中的第一个代码片段相同的事情。唯一的区别是我的代码允许浮点数字存在偏差-因此你可以平滑地更改概率。你正在使用g整数,它是一个
roll = (int)(91*(asin(Math.rand()*a)/asin(a)))
private int[] chooseProblem(float bias, int[] currentShuffle) { 
// if bias == 0, we choose from uniform distribution
// for 0 < bias <= 1, we choose from increasingly biased distribution
// for bias > 1, we choose from uniform distribution
// array currentShuffle contains the numbers 0..90, initially in shuffled order
// when a problem is solved correctly it is moved to the top of the pile
// when it is wrong, it is moved to the bottom.
// return value contains number1, number2, and the current position of the problem in the list
    int problem, problemIndex;

    if(bias < 0 || bias > 1) bias = 0;

    if(bias == 0) {
        problem = random.nextInt(91);
        problemIndex = problem;
    }
    else {
        float x = asin(Math.random()*bias)/asin(bias);
        problemIndex = Math.floor(91*x);
        problem = currentShuffle[problemIndex];
    }

    // now convert "problem number" into two numbers:
    int first, last;    
    first = (int)((Math.sqrt(8*problem + 1)-1)/2);
    last = problem - first * (first+1) / 2;

    // and return the result:
    return {first, last, problemIndex};
}


private void shuffleProblems(int[] currentShuffle, int upDown) {
// when upDown==0, return a randomly shuffled array
// when upDown < 0, (wrong answer) move element[-upDown] to zero
// when upDown > 0, (correct answer) move element[upDown] to last position
// note - if problem 0 is answered incorrectly, don't call this routine!

    int ii, temp, swap;

    if(upDown == 0) {

        // first an ordered list:
        for(ii=0;ii<91;ii++) {
            currentShuffle[ii]=ii;
        }

        // now shuffle it:
        for(ii=0;ii<91;ii++) {
            temp = currentShuffle[ii];
            swap = ii + random.nextInt(91-ii);
            currentShuffle[ii]=currentShuffle[swap];
            currentShuffle[swap]=temp;
        }
        return;
    }

    if(upDown < 0) {
        temp = currentShuffle[-upDown];
        for(ii = -upDown; ii>0; ii--) {
            currentShuffle[ii]=currentShuffle[ii-1];
        }
        currentShuffle[0] = temp;
    }
    else {
        temp = currentShuffle[upDown];
        for(ii = upDown; ii<90; ii++) { 
            currentShuffle[ii]=currentShuffle[ii+1];
        }
        currentShuffle[90] = temp;
    }
    return;
}


// main problem posing loop:

int[] currentShuffle = new int[91];
int[] newProblem;
int keepGoing = 1;

// initial shuffle:
shuffleProblems( currentShuffle, 0); // initial shuffle

while(keepGoing) {
    newProblem = chooseProblem(bias, currentShuffle);
    // pose the problem, get the answer
    if(wrong) {
        if(newProblem > 0) shuffleProblems( currentShuffle, -newProblem[2]);
    }
    else shuffleProblems( currentShuffle, newProblem[2]);
    // decide if you keep going...
}