Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
526 views
in Technique[技术] by (71.8m points)

php - Why would rand() return a negative value when min and max values are positive?

I have a simple piece of PHP code which requires a random number to be created. However, even though the input is always positive, it sometimes returns a negative output.

Here's my debug code:

$debt = rand($this->gdp * 0.02, $this->gdp * 0.17);
echo "<p>GDP: ".$this->gdp." rand(".$this->gdp * 0.02."  , ".$this->gdp * 0.17.") = <strong>".$debt."</strong></p>";

Here's an example output:

GDP: 219254674605 rand(4385093492.1 , 37273294682.85) = 75276999

GDP: 345015694865 rand(6900313897.3 , 58652668127.05) = -1636353016

GDP: 90445390920 rand(1808907818.4 , 15375716456.4) = -165604705

GDP: 3412849650 rand(68256993 , 580184440.5) = 347516196

GDP: 2939111315 rand(58782226.3 , 499648923.55) = 119181875

GDP: 26369065 rand(527381.3 , 4482741.05) = 3632416

GDP: 215838135 rand(4316762.7 , 36692482.95) = 28784811

GDP: 511763530 rand(10235270.6 , 86999800.1) = 39954394

GDP: 42416245 rand(848324.9 , 7210761.65) = 3974882

GDP: 75090235 rand(1501804.7 , 12765339.95) = 5201966

So why would a rand() of two positive numbers give a negative return?

Any help would be much appreciated!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Because you're seeing an integer overflow in the arguments.

According to the rand() documentation it takes two int values as arguments. On a 32-bit machine those are 32 bit as well (at least for PHP). So when you pass arguments larger than 231 − 1 they overflow and start at −231 again.

Apparently, if you need larger values you'll have to code it yourself. While simply creating a 64-bit number from two 32-bit numbers works as intended, you can't simply do a modulo operation with your maximum value since that skews the distribution. For a good implementation how to generate a uniformly-distributed random integer between 0 and a certain upper bound you can take a look at java.util.Random.nextInt(int) and adapt accordingly for 64 bit integers.

mt_rand() while usually a nice choice for random numbers because it uses MT19937 instead of a poor LCG, doesn't help here either as its arguments are ints as well.


Another option you might want to consider if you don't require every possible value to be picked eventually:

  • Generate a random floating-point value between 0 and 1 by calling

    $rnd = mt_rand() / (double)mt_getrandmax()
    
  • Determine the range of numbers you need:

    $min = $this->gdp * 0.02;
    $max = $this->gdp * 0.17;
    $range = $max - $min;
    
  • Multiply this by the previously-obtained random floating-point value and add the minimum:

    $value = $min + $range * $rnd
    
  • Now you have a random value between your chosen boundaries. It's approximately uniformly distributed, although there are discrete steps between adjacent random numbers as you are stretching 32 bits of randomness over a larger number of bits. If that's no problem for you, go ahead, though.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...