Random Float between 0 and 1 in PHP

前端 未结 13 2683
粉色の甜心
粉色の甜心 2020-12-01 23:44

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().

相关标签:
13条回答
  • 2020-12-01 23:45

    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).

    0 讨论(0)
  • 2020-12-01 23:46

    Solution for PHP 7. Generates random number in [0,1). i.e. includes 0 and excludes 1.

    function random_float() {
        return random_int(0, PHP_INT_MAX-1)/PHP_INT_MAX;
    }
    
    0 讨论(0)
  • 2020-12-01 23:48
    $random_number = rand(1,10).".".rand(1,9);
    
    0 讨论(0)
  • 2020-12-01 23:49
    function frand($min, $max, $decimals = 0) {
      $scale = pow(10, $decimals);
      return mt_rand($min * $scale, $max * $scale) / $scale;
    }
    
    echo "frand(0, 10, 2) = " . frand(0, 10, 2) . "\n";
    
    0 讨论(0)
  • 2020-12-01 23:51
    rand(0,1000)/1000 returns:
    0.348 0.716 0.251 0.459 0.893 0.867 0.058 0.955 0.644 0.246 0.292
    

    or use a bigger number if you want more digits after decimal point

    0 讨论(0)
  • 2020-12-01 23:52

    Example from documentation :

    function random_float ($min,$max) {
       return ($min+lcg_value()*(abs($max-$min)));
    }
    
    0 讨论(0)
提交回复
热议问题