Home > Software design >  Smart algorithm to randomize a Double in range but with odds
Smart algorithm to randomize a Double in range but with odds

Time:07-17

I use the following function to generate a random double in a specific range :

nextDouble(1.50, 7.00)

However, I've been trying to come up with an algorithm to make the randomization have higher probability to generate a double that is close to the 1.50 than it is to 7.00. Yet I don't even know where it starts. Anything come to mind ?

Java is also welcome.

CodePudding user response:

You should start by discovering what probability distribution you need. Based on your requirements, and assuming that random number generations are independent, perhaps Poisson distribution is what you are looking for:

a call center receives an average of 180 calls per hour, 24 hours a day. The calls are independent; receiving one does not change the probability of when the next one will arrive. The number of calls received during any minute has a Poisson probability distribution with mean 3: the most likely numbers are 2 and 3 but 1 and 4 are also likely and there is a small probability of it being as low as zero and a very small probability it could be 10.

The usual probability distributions are already implemented in libraries e.g. org.apache.commons.math3.distribution.PoissonDistribution in Apache Commons Math3.

CodePudding user response:

What you could do is to 'correct' the random with a factor in the direction of 1.5. You would create some sort of bias factor. Like this:

        @Test
    void DoubleTest() {
    double origin = 1.50;
    final double fiarRandom = new Random().nextDouble(origin, 7);
    System.out.println(fiarRandom);

    double biasFactor = 0.9;
    final double biasedDiff = (fiarRandom - origin) * biasFactor;

    double biasedRandom = origin   biasedDiff;

    System.out.println(biasedRandom);
}

The lower you set the bias factor (must be >0 & <= 1), the stronger your bias towards 1.50.

CodePudding user response:

You can take a straightforward approach. As you said you want a higher probability of getting the value closer to 1.5 than 7.00, you can even set the probability. So, here their average is (1.5 7)/2 = 4.25.

So let's say I want a 70% probability that the random value will be closer to 1.5 and a 30% probability closer to 7.

double finalResult;
double mid = (1.5 7)/2;
double p = nextDouble(0,100);
if(p<=70) finalResult = nextDouble(1.5,mid);
else finalResult = nextDouble(mid,7);

Here, the final result has 70% chance of being closer to 1.5 than 7.

As you did not specify the 70% probability you can even make it random. you just have to generate nextDouble(50,100) which will give you a value more than or equal 50% and less than 100% which you can use later to apply this probability for your next calculation. Thanks

CodePudding user response:

I suggest to not think about this problem in terms of generating a random number with irregular probability. Instead, think about generating a random number normally in a some range, but then map this range into another one in non-linear way.

Let's split our algorithm into 3 steps:

  1. Generate a random number in <0, 1) range linearly (so using a standard random generator).
  2. Map it into another <0, 1) range in non-linear way.
  3. Map the resulting <0, 1) into <1.5, 7) linearly.

Steps 1. and 3. are easy, the core of our algorithm is 2. We need a way to map <0, 1) into another <0, 1), but non-linearly, so e.g. 0.7 does not have to produce 0.7. Classic math helps here, we just need to look at visual representations of algebraic functions.

In your case you expect that while the input number increases from 0 to 1, the result first grows very slowly (to stay near 1.5 for a longer time), but then it speeds up. This is exactly how e.g. y = x ^ 2 function looks like. Your resulting code could be something like:

fun generateDouble(): Double {
    val step1 = Random.nextDouble()
    val step2 = step1.pow(2.0)
    val step3 = step2 * 5.5   1.5
    return step3
}

or just:

fun generateDouble() = Random.nextDouble().pow(2.0) * 5.5   1.5

By changing the exponent to bigger numbers, the curve will be more aggressive, so it will favor 1.5 more. By making the exponent closer to 1 (e.g. 1.4), the result will be more close to linear, but still it will favor 1.5. Making the exponent smaller than 1 will start to favor 7.

You can also look at other algebraic functions with this shape, e.g. y = 2 ^ x - 1.

  • Related