Random Float between 0 and 1 in PHP

2019-01-09 14:21发布

How does one generate a random float between 0 and 1 in PHP?

I'm looking for the PHP's equivalent to Java's Math.random().

标签: php random
12条回答
乱世女痞
2楼-- · 2019-01-09 14:50
function mt_rand_float($min, $max, $countZero = '0') {
    $countZero = +('1'.$countZero);
    $min = floor($min*$countZero);
    $max = floor($max*$countZero);
    $rand = mt_rand($min, $max) / $countZero;
    return $rand;
}

example:

echo mt_rand_float(0, 1);

result: 0.2

echo mt_rand_float(3.2, 3.23, '000');

result: 3.219

echo mt_rand_float(1, 5, '00');

result: 4.52

echo mt_rand_float(0.56789, 1, '00');

result: 0.69

查看更多
啃猪蹄的小仙女
3楼-- · 2019-01-09 14:51

You may use the standard function: lcg_value().

Here's another function given on the rand() docs:

// auxiliary function
// returns random number with flat distribution from 0 to 1
function random_0_1() 
{
    return (float)rand() / (float)getrandmax();
}
查看更多
男人必须洒脱
4楼-- · 2019-01-09 14:53

Example from documentation :

function random_float ($min,$max) {
   return ($min+lcg_value()*(abs($max-$min)));
}
查看更多
Melony?
5楼-- · 2019-01-09 14:57

Most answers are using mt_rand. However, mt_getrandmax() usually returns only 2147483647. That means you only have 31 bits of information, while a double has a mantissa with 52 bits, which means there is a density of at least 2^53 for the numbers between 0 and 1.

This more complicated approach will get you a finer distribution:

function rand_754_01() {
    // Generate 64 random bits (8 bytes)
    $entropy = openssl_random_pseudo_bytes(8);
    // Create a string of 12 '0' bits and 52 '1' bits. 
    $x = 0x000FFFFFFFFFFFFF;
    $first12 = pack("Q", $x);
    // Set the first 12 bits to 0 in the random string. 
    $y = $entropy & $first12;
    // Now set the first 12 bits to be 0[exponent], where exponent is randomly chosen between 1 and 1022. 
    // Here $e has a probability of 0.5 to be 1022, 0.25 to be 1021, etc. 
    $e = 1022;     
    while($e > 1) {   
        if(mt_rand(0,1) == 0) {
            break;
        } else {
            --$e;
        }
    }
    // Pack the exponent properly (add four '0' bits behind it and 49 more in front)
    $z = "\0\0\0\0\0\0" . pack("S", $e << 4);
    // Now convert to a double. 
    return unpack("d", $y | $z)[1];          
}

Please note that the above code only works on 64-bit machines with a Litte-Endian byte order and Intel-style IEEE754 representation. (x64-compatible computers will have this). Unfortunately PHP does not allow bit-shifting past int32-sized boundaries, so you have to write a separate function for Big-Endian.

You should replace this line:

    $z = "\0\0\0\0\0\0" . pack("S", $e << 4);

with its big-endian counterpart:

    $z = pack("S", $e << 4) .  "\0\0\0\0\0\0";

The difference is only notable when the function is called a large amount of times: 10^9 or more.

Testing if this works

It should be obvious that the mantissa follows a nice uniform distribution approximation, but it's less obvious that a sum of a large amount of such distributions (each with cumulatively halved chance and amplitude) is uniform.

Running:

function randomNumbers() {
    $f = 0.0;
    for($i = 0; $i < 1000000; ++$i) {
        $f += \math::rand_754_01();
    }
    echo $f / 1000000;
}

Produces an output of 0.49999928273099 (or a similar number close to 0.5).

查看更多
三岁会撩人
6楼-- · 2019-01-09 14:58
class SomeHelper
{
     /**
     * Generate random float number.
     *
     * @param float|int $min
     * @param float|int $max
     * @return float
     */
    public static function rand($min = 0, $max = 1)
    {
        return ($min + ($max - $min) * (mt_rand() / mt_getrandmax()));
    }
}
查看更多
贼婆χ
7楼-- · 2019-01-09 14:59
$random_number = rand(1,10).".".rand(1,9);
查看更多
登录 后发表回答