Harry Sinfield
Harry Sinfield

Reputation: 99

Php random number generate

My task:

Generate random numbers between 1 and 20, to 1 decimal place.

However my issue as simple as mt_rand. I want most of the numbers generated to be lower around 0.5 - 4.5 with the occasional number being between 4.5-10 and very rarely say once every 12-20 hours being between 10-20.

I've been using the following but have no idea where to go from. I am a very basic self-taught programmer.

$min = 1;
$max = 20;
$suisse_interest = mt_rand ($min*10, $max*10) / 10

Maybe if I briefly explain why I want this it may help..

I own an online game and want to add 3 "banks" with each bank generating different interests each hour. Most of the time I want it low, but sometimes higher and very rarely very high (15-20%).

With the above code the random number goes too high to often.

Any help with this is greatly appreciated!

Upvotes: 4

Views: 714

Answers (3)

kuroi neko
kuroi neko

Reputation: 8661

This is not a PHP-specific problem.

What you need is a non-linear probability law, that you can then implement in PHP.

If you want something centered around an average value, the ideal would be a gaussian aka normal distribution, but computing it requires various complicated tricks, most of them being optimized for rapid generation at the cost of increasing complexity.

If you generate only a few values each hour, performance will not be an issue.

A reasonable approximation would be to sum 3 or 4 random variables, taking advantage of the central limit theorem.

Summing random values between 0 and twice your middle rate will create an approximation of a gaussian centered around your middle value. You can then clamp values inferior to the middle point if you don't want low rates. The net result would be 50% chances of getting middle rate and a steadily decreasing chance to get up to twice that value.

An increasing number of sums will "narrow" the curve, making it less likely to get a high value.

for instance:

define ("INTEREST_MEAN", 10);
define ("INTEREST_SPREAD", 5);
function random_interest ()
{
    $res = 0;
    for ($i = 0 ; $i != INTEREST_SPREAD ; $i++) $res += mt_rand(0, 2*INTEREST_MEAN);
    $res /= INTEREST_SPREAD; // normalize the sum to get a mean-centered result
    $res = max ($res, INTEREST_MEAN); // clamp lower values
}

Upvotes: 0

ByteHamster
ByteHamster

Reputation: 4951

You need an exponential calculation. If you use a function similar to the following function, the probability for low numbers increases. Of course you need to adapt the numbers a bit to provide an output suiting your needs.

$i = 0;
while($i<30) {
    $i++;
    $rand = mt_rand(0, 7000) / 100; // 0.0 ~ 70.0
    // This is the most important line:
    $output = round( 20*(pow(0.95,$rand)) , 1);
    echo "$output ";
}

Sample output:

1.8  4.3  2.6  5.5  3.7  15.5  1.6  0.6  0.6  1.6  5.8  
1.3  6.1  3.2  0.8  1.7  14.7  7.9  1.3  10.3  5.5  12.6  
1.5  8.4  1.5  0.9  13.3  5.8  7.5  1.7  

As you see, mostly smaller number are printed.

Chart

The probability to get 20 is around 1.4% in my code whereas the probability to get a number smaller than 5 is around 78%

Upvotes: 3

Wilon
Wilon

Reputation: 117

Try this.The probability to 1.0~4.5 is around 96%, 4.5~10.0 is around 2%, and 10.0~20.0 is around 2%.

<?php
    // 1.0~4.5    96%
    // 4.5~10.0   2%
    // 10.0~20.0  2%

    function fun() {
        $num = mt_rand(1, 100);
        if ($num > 0 && $num <= 96) {
            $return = mt_rand(10, 45) / 10;  // 96%
        } else if ($num > 96 && $num <= 98) {
            $return = mt_rand(45, 100) / 10;  // 2%
        } else {
            $return = mt_rand(100, 200) / 10;  // 2%
        }
        return sprintf("%01.1f",$return);
    }

    echo fun();
?>

Upvotes: 2

Related Questions