LetsGo
LetsGo

Reputation: 23

Get a random number within a range with a bias

Hello i am trying to make a method to generate a random number within a range where it can take a Bias that will make the number more likely to be higher/lower depending on the bias.

To do this currently i was using this

 public int randIntWeightedLow(int max, int min, int rolls){

    int rValue = 100;

    for (int i = 0; i < rolls ; i++) {
        int rand = randInt(min, max);

        if (rand < rValue ){
            rValue = rand;
        }
    }

    return rValue;
}

This works okay by giving me a number in the range and the more rolls i add the likely the number will be low. However the problem i am running in to is that the there is a big difference between having 3 rolls and 4 rolls.

I am loking to have somthing like public void randomIntWithBias(int min, int max, float bias){ }

Where giving a negative bias would make the number be low more often and a positive bias make the number be higher more often but still keeping the number in the random of the min and max.

Currently to generate a random number i am using

 public int randInt(final int n1, final int n2) {
    if (n1 == n2) {
        return n1;
    }

    final int min = n1 > n2 ? n2 : n1;
    final int max = n1 > n2 ? n1 : n2;

    return rand.nextInt(max - min + 1) + min;
}

I am new to java and coding in general so any help would be greatly appreciated.

Upvotes: 2

Views: 382

Answers (1)

Severin Pappadeux
Severin Pappadeux

Reputation: 20080

Ok, here is quick sketch how it could be done.

First, I propose to use Apache commons java library, it has sampling for integers with different probabilities already implemented. We need Enumerated Integer Distribution.

Second, two parameters to make distribution look linear, p0 and delta. For kth value relative probability would be p0 + k*delta. For delta positive larger numbers will be more probable, for delta negative smaller numbers will be more probable, delta=0 equal to uniform sampling.

Code (my Java is rusty, please bear with me)

import org.apache.commons.math3.distribution.EnumeratedIntegerDistribution;

public int randomIntWithBias(int min, int max, double p0, double delta){
    if (p0 < 0.0)
        throw new Exception("Negative initial probability");        
    int N = max - min + 1; // total number of items to sample

    double[] p = new double[N]; // probabilities
    int[] items = new int[N]; // items

    double sum = 0.0; // total probabilities summed
    for(int k = 0; k != N; ++k) { // fill arrays
        p[k] = p0 + k*delta;
        sum += p[k];
        items[k] = min + k;
    }

    if (delta < 0.0) { // when delta negative we could get negative probabilities
       if (p[N-1] < 0.0) // check only last probability
           throw new Exception("Negative probability");
    }

    for(int k = 0; k != N; ++k) { // Normalize probabilities
        p[k] /= sum;
    }

    EnumeratedIntegerDistribution rng = new EnumeratedIntegerDistribution(items, p);

    return rng.sample();
}

That's the gist of the idea, code could be (and should be) optimized and cleaned.

UPDATE

Of course, instead of linear bias function you could put in, say, quadratic one. General quadratic function has three parameters - pass them on, fill in a similar way array of probabilities, normalize, sample

Upvotes: 2

Related Questions