php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #69396 Strange behavior of rand function with specific big $max value
Submitted: 2015-04-07 20:13 UTC Modified: 2017-12-26 12:19 UTC
Votes:2
Avg. Score:3.5 ± 0.5
Reproduced:2 of 2 (100.0%)
Same Version:2 (100.0%)
Same OS:1 (50.0%)
From: mariusz at mariuszgil dot pl Assigned: nikic (profile)
Status: Closed Package: *Math Functions
PHP Version: 5.5.23 OS: Mac, Linux
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: mariusz at mariuszgil dot pl
New email:
PHP Version: OS:

 

 [2015-04-07 20:13 UTC] mariusz at mariuszgil dot pl
Description:
------------
With specific big $max value, rand(0, $max) function returns unexpected, strange values. 

Test script creates an array with numbers of occurences rand(0, $max) % $n results. Expected result is an array with all values (almost) equal, with big $iter value.

But when $max is equal:
- getrandmax() * 2
- getrandmax() * 2 + 1
- getrandmax() * 2 + 2
returned array looks like:

array(16) {
  [0]=>
  int(0)
  [1]=>
  int(124837)
  [2]=>
  int(0)
  [3]=>
  int(125168)
  [4]=>
  int(0)
  [5]=>
  int(124687)
  [6]=>
  int(0)
  [7]=>
  int(125015)
  [8]=>
  int(0)
  [9]=>
  int(124685)
  [10]=>
  int(0)
  [11]=>
  int(125265)
  [12]=>
  int(0)
  [13]=>
  int(125077)
  [14]=>
  int(0)
  [15]=>
  int(125266)
}

When $max is equal:
- getrandmax() * 2 + 4
- getrandmax() * 2 + 6
- getrandmax() * 2 + 8
- getrandmax() * 2 + 10
- ...
distribution of counters looks very strange, like:

array(16) {
  [0]=>
  int(83187)
  [1]=>
  int(41787)
  [2]=>
  int(83074)
  [3]=>
  int(41420)
  [4]=>
  int(83377)
  [5]=>
  int(41756)
  [6]=>
  int(83319)
  [7]=>
  int(41941)
  [8]=>
  int(83469)
  [9]=>
  int(41925)
  [10]=>
  int(83327)
  [11]=>
  int(41544)
  [12]=>
  int(83287)
  [13]=>
  int(41528)
  [14]=>
  int(83098)
  [15]=>
  int(41961)
}

Probably, when $max is greater then getrandmax(), an error/notice should be generated.


Test script:
---------------
<?php

$iter = 1000000;
$max = getrandmax() * 2;
$n = 16;

$values = array_fill(0, $n, 0);

for ($i = 0; $i < $iter; $i++) {
        $values[rand(0, $max) % $n] += 1;
}

var_dump($values);

Expected result:
----------------
Expected results of test script is something similiar to:

array(16) {
  [0]=>
  int(62287)
  [1]=>
  int(62495)
  [2]=>
  int(62638)
  [3]=>
  int(62791)
  [4]=>
  int(62386)
  [5]=>
  int(62533)
  [6]=>
  int(62921)
  [7]=>
  int(62532)
  [8]=>
  int(62971)
  [9]=>
  int(62541)
  [10]=>
  int(62854)
  [11]=>
  int(61833)
  [12]=>
  int(62269)
  [13]=>
  int(62305)
  [14]=>
  int(62351)
  [15]=>
  int(62293)
}

when all values are close to each other.


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2015-04-08 13:54 UTC] cmb@php.net
-Status: Open +Status: Verified
 [2015-04-08 13:54 UTC] cmb@php.net
At least in NTS builds, for $max > getrandmax() PHP calls the PRNG
of the C library and simply scales up the returned value, so some
values will be never be generated. For instance, rand(0, 2 *
getrandmax() + 1) will (usually) never return an odd value.

Instead of emitting a notice when $max > getrandmax(), or even
changing the behavior, it might be sufficient to change the
documentation accordingly.
 [2017-12-26 12:19 UTC] nikic@php.net
-Status: Verified +Status: Closed -Assigned To: +Assigned To: nikic
 [2017-12-26 12:19 UTC] nikic@php.net
This has been fixed in PHP 7.1.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 28 13:01:28 2024 UTC