在PHP中,如何生成一个大的伪随机数?

时间:2021-07-11 09:11:36

I'm looking for a way to generate a big random number with PHP, something like:

我正在寻找一种用PHP生成一个大随机数的方法,例如:

mt_rand($lower, $upper);

The closer I've seen is gmp_random() however it doesn't allow me to specify the lower and upper boundaries only the number of bits per limb (which I've no idea what it is).

我看到的距离越近gmp_random()但它不允许我指定下边界和上边界只有每个肢体的位数(我不知道它是什么)。

EDIT: Axsuuls answer seems to be pretty close to what I want and very similar to gmp_random however there seems to be only one flaw in one scenario.

编辑:Axsuuls答案似乎非常接近我想要的,非常类似于gmp_random,但在一个场景中似乎只有一个缺陷。

Suppose I wan't to get a random number between:

假设我不想在两者之间得到一个随机数:

  • 1225468798745475454898787465154

and:

  • 1225468798745475454898787465200

So if the function is called BigRandomNumber():

因此,如果函数名为BigRandomNumber():

BigRandomNumber($length = 31);

This can easily return 9999999999999999999999999999999 which is out of the specified boundary.

这很容易返回超出指定边界的9999999999999999999999999999999。

How can I use a min / max boundary instead of a length value?

如何使用最小/最大边界而不是长度值?

BigRandomNumber('1225468798745475454898787465154', '1225468798745475454898787465200');

This should return a random number between 1225468798745475454898787465 [154 .. 200].

这应该返回1225468798745475454898787465 [154 .. 200]之间的随机数。

For the reference I believe the solution might have to make use of the function supplied in this question.

作为参考,我认为解决方案可能必须使用此问题中提供的功能。

EDIT: The above post was deleted, here it is:

编辑:上面的帖子被删除了,这里是:

function compare($number1, $operator, $number2) {
  $x = bccomp($number1, $number2);

  switch($operator) {
    case '<':
      return -1===$x;
    case '>':
      return 1===$x;
    case '=':
    case '==':
    case '===':
      return 0===$x;
    case '!=':
    case '!==':
    case '<>':
      return 0!==$x;
  }
}

12 个解决方案

#1


15  

Try the following:

请尝试以下方法:

function BigRandomNumber($min, $max) {
  $difference   = bcadd(bcsub($max,$min),1);
  $rand_percent = bcdiv(mt_rand(), mt_getrandmax(), 8); // 0 - 1.0
  return bcadd($min, bcmul($difference, $rand_percent, 8), 0);
}

The math is as following: multiply the difference between the minimum and maximum by a random percentage, and add to the minimum (with rounding to an int).

数学如下:将最小值和最大值之间的差乘以随机百分比,并加到最小值(舍入为int)。

#2


6  

What you really need to know is the relative gap; if it's small then you can generate a number from 0 to the maximum gap then add the minimum to that.

你真正需要知道的是相对差距;如果它很小,那么你可以生成一个从0到最大间隙的数字,然后加上最小值。

#3


2  

This will give you more zeros in your giant random number and you can also specify the length of the giant random number (can your giant random number start with a 0? if not, that can also be easily implemented)

这会在你的巨型随机数中给你更多的零,你也可以指定巨大随机数的长度(你的巨型随机数可以从0开始吗?如果没有,也可以很容易实现)

<?php

$randNumberLength = 1000;  // length of your giant random number
$randNumber = NULL;

for ($i = 0; $i < $randNumberLength; $i++) {
    $randNumber .= rand(0, 9);  // add random number to growing giant random number

}

echo $randNumber;

?>

Good luck!

#4


1  

What you can do is create a few smaller random numbers and combine them. Not sure on how large you actually need though.

你可以做的是创建一些较小的随机数并组合它们。不确定你实际需要多大。

#5


0  

$lower = gmp_com("1225468798745475454898787465154");
$upper = gmp_com("1225468798745475454898787465200");

$range_size = gmp_sub($upper, $lower);

$rand = gmp_random(31);
$rand = gmp_mod($rand, $range_size);

$result = gmp_add($rand, $lower);

Totally untested :-)

完全未经测试:-)

#6


0  

This might work for you. (I am not sure why you need it, so it might not be the best way to do it, but it should fit your requirements):

这可能对你有用。 (我不确定你为什么需要它,所以它可能不是最好的方法,但它应该符合你的要求):

<?php
function bigRandomNumber($min, $max)
{
 // check input first
    if ($max < $min) { return false; }
    // Find max & min length of the number
    $lenMin = strlen ($min);
    $lenMax = strlen ($max);

    // Generate a random length for the random number
    $randLen = $lenMin + mt_rand(0, $lenMax - $lenMin);
    /* Generate the random number digit by digit, 
       comparing it with the min and max values */
 $b_inRange = false;
    for ($i = 0; $i < $randLen; $i++)
 {
  $randDigit = mt_rand(0,9);

  /* As soon as we are sure that the number will stay 
          in range, we can stop comparing it to min and max */
  if (!$b_inRange)
  {
   $tempRand = $rand . $randDigit;
   $tempMin = substr($min, 0, $i+1);
   $tempMax = substr($max, 0, $i+1);
   // Make sure that the temporary random number is in range
   if ($tempRand < $tempMin || $tempRand > $tempMax)
   {
    $lastDigitMin = substr($tempMin, -1);
    $lastDigitMax = substr($tempMax, -1);
    $tempRand = $rand . @mt_rand($lastDigitMin, $lastDigitMax);
   }
   /* Check if $tempRand is equal to the min or to the max value. 
               If it is not equal, then we know it will stay in range */
   if ($tempRand > $tempMin && $tempRand < $tempMax)
   {
    $b_inRange = true;
   }
  }
  else
  {
   $tempRand = $rand . $randDigit;
  }
  $rand = $tempRand;  
 }
 return $rand;
}

I tried a couple times and it looks like it works OK. Optimize if needed. The idea is to start by figuring out a random length for your random number that would put it in the acceptable range. Then generate random digits one by one up to that length by concatenating. If it is not in range, generate a new random digit in range and concatenate.

我尝试过几次,看起来效果还可以。如果需要优化。我们的想法是首先确定随机数的随机长度,使其处于可接受的范围内。然后通过连接逐个生成随机数字到该长度。如果它不在范围内,则在范围内生成一个新的随机数并连接。

I use the fact that PHP will convert a string to a number to take advantage of the string functions. Of course this generates a warning for mt_rand, but as we use only numbers, it should be safe to suppress it.

我使用PHP将字符串转换为数字以利用字符串函数的事实。当然这会为mt_rand生成警告,但由于我们只使用数字,所以应该可以安全地抑制它。

Now, I have to say that I am quite curious as to why you need this in the first place.

现在,我不得不说,我很好奇为什么你首先需要这个。

#7


0  

/* Inputs: 
 * min - GMP number or string: lower bound
 * max - GMP number or string: upper bound
 * limiter - GMP number or string: how much randomness to use.
 *  this value is quite obscure (see `gmp_random`, but the default
 *  supplies several hundred bits of randomness, 
 *  which is probably enough.
 * Output: A random number between min (inclusive) and max (exclusive).
*/
function BigRandomNumber($min, $max, $limiter = 20) {
  $range = gmp_sub($max, $min);
  $random = gmp_random();
  $random = gmp_mod($random, $range);
  $random = gmp_add($min, $random);
  return $random;
}

This is just the classic formula rand_range($min, $max) = $min + rand() % ($max - $min) translated to arbitrary-precision arithmetic. It can exhibit a certain amount of bias if $max - $min isn't a power of two, but if the number of bits of randomness is high enough compared to the size of $max - $min the bias becomes negligible.

这只是经典公式rand_range($ min,$ max)= $ min + rand()%($ max - $ min)转换为任意精度算术。如果$ max - $ min不是2的幂,它可能会表现出一定的偏差,但如果随机性的位数与$ max - $ min的大小相比足够高,则偏差变得可以忽略不计。

#8


0  

This may work:

这可能有效:

  • Split the number into an array with 9 numbers or less ("the rest") ... 9 chars because max rand number is 2147483647 on my machine.
  • 将数字拆分为9个或更少的数字(“其余”)... 9个字符,因为我的机器上的最大兰特数是2147483647。

  • For each "9-or-less numbers array block", create a random number.
  • 对于每个“9或更少数字数组块”,创建一个随机数。

  • Implode the array and you will now have a usable random number.
  • 内爆数组,您现在将拥有一个可用的随机数。

Example code that illustrates the idea (notice: the code is undone)

示例代码说明了这个想法(注意:代码被撤消)

function BigRandomNumber($min,$max) {
// Notice: Will only work when both numbers have same length.
echo (strlen($min) !== strlen($max)) ? "Error: Min and Max numbers must have same length" : NULL;
$min_arr = str_split($min);
$max_arr = str_split($max);
// TODO: This loop needs to operate on 9 chars ($i will increment by $i+9)
for($i=0; $i<=count($max_arr); $i++) {
    if($i == 0) {
        // First number: >=first($min) and <=first($max).
        $new_arr[$i] = rand( $min_arr[0], $max_arr[0]);
    } else if($i == count($max_arr)) {
        // Last number <= $max .. not entirely correct, feel free to correct it.
        $new_arr[$i] = rand(0, substr($max,-1));
    } else {
        $new_arr[$i] = rand(0,9);
    }
}
return implode($new_arr);
}

#9


0  

Tested and works

经过测试和工作

<?php 

$min = "1225468798745475454898787465154";
$max = "1225468798745475454898787465200";

$bigRandNum = bigRandomNumber($min,$max);
echo "The Big Random Number is: ".$bigRandNum."<br />";

function bigRandomNumber($min,$max) {
    // take the max number length
    $number_length = strlen($max);

    // Set the counter
    $i = 1;

    // Find the base and the min and max ranges
    // Loop through the min to find the base number
    while ($i <= $number_length) {
        $sub_string = substr($min, 0, $i);

        // format pattern
        $format_pattern = '/'.$sub_string.'/';
        if (!preg_match($format_pattern, $max)) {
            $base = $sub_string;

            // Set the min and max ranges
            $minRange = substr($min, ($i - 1), $number_length);
            $maxRange = substr($max, ($i - 1), $number_length);

            // End while loop, we found the base
            $i = $number_length;
        }
        $i++;
    }
    // find a random number with the min and max range
    $rand = rand($minRange, $maxRange);

    // add the base number to the random number
    $randWithBase = $base.$rand;

    return $randWithBase;
}

?>

#10


0  

Generating 'n' random chars is not really an option, as random('9999999999') could still, theoretically, return 1...

生成'n'个随机字符实际上不是一个选项,因为随机('9999999999')理论上仍然可以返回1 ...

Here's a quite simple function:

这是一个非常简单的功能:

function bcrand($max) { 
    return bcmul($max, (string)mt_rand() / mt_getrandmax() ); 
}

Note that it will NOT return N bits of randomness, just adjust scale

请注意,它不会返回N位随机性,只需调整比例

#11


-1  

Take your floor and and your random number in the range to it.

把你的地板和随机数放在范围内。

1225468798745475454898787465154 + rand(0, 6)

#12


-1  

Here is pseudocode:

这是伪代码:


// generate a random number between N1 and N2

rangesize = N2 - N1 + 1
randlen = length(rangesize) + 4 // the 4 is to get more digits to reduce bias
temp = BigRandomNumber(randlen) // generate random number, "randlen" digits long
temp = temp mod rangesize
output N1 + temp

Notes:

  • all arithmetic here (except in the second line) must be arbitrary precision: use the bcmath library for this
  • 这里的所有算术(第二行除外)必须是任意精度:为此使用bcmath库

  • in the second line, "length" is number of digits, so the "length" of 1025 would be 4
  • 在第二行中,“length”是位数,因此1025的“length”将是4

#1


15  

Try the following:

请尝试以下方法:

function BigRandomNumber($min, $max) {
  $difference   = bcadd(bcsub($max,$min),1);
  $rand_percent = bcdiv(mt_rand(), mt_getrandmax(), 8); // 0 - 1.0
  return bcadd($min, bcmul($difference, $rand_percent, 8), 0);
}

The math is as following: multiply the difference between the minimum and maximum by a random percentage, and add to the minimum (with rounding to an int).

数学如下:将最小值和最大值之间的差乘以随机百分比,并加到最小值(舍入为int)。

#2


6  

What you really need to know is the relative gap; if it's small then you can generate a number from 0 to the maximum gap then add the minimum to that.

你真正需要知道的是相对差距;如果它很小,那么你可以生成一个从0到最大间隙的数字,然后加上最小值。

#3


2  

This will give you more zeros in your giant random number and you can also specify the length of the giant random number (can your giant random number start with a 0? if not, that can also be easily implemented)

这会在你的巨型随机数中给你更多的零,你也可以指定巨大随机数的长度(你的巨型随机数可以从0开始吗?如果没有,也可以很容易实现)

<?php

$randNumberLength = 1000;  // length of your giant random number
$randNumber = NULL;

for ($i = 0; $i < $randNumberLength; $i++) {
    $randNumber .= rand(0, 9);  // add random number to growing giant random number

}

echo $randNumber;

?>

Good luck!

#4


1  

What you can do is create a few smaller random numbers and combine them. Not sure on how large you actually need though.

你可以做的是创建一些较小的随机数并组合它们。不确定你实际需要多大。

#5


0  

$lower = gmp_com("1225468798745475454898787465154");
$upper = gmp_com("1225468798745475454898787465200");

$range_size = gmp_sub($upper, $lower);

$rand = gmp_random(31);
$rand = gmp_mod($rand, $range_size);

$result = gmp_add($rand, $lower);

Totally untested :-)

完全未经测试:-)

#6


0  

This might work for you. (I am not sure why you need it, so it might not be the best way to do it, but it should fit your requirements):

这可能对你有用。 (我不确定你为什么需要它,所以它可能不是最好的方法,但它应该符合你的要求):

<?php
function bigRandomNumber($min, $max)
{
 // check input first
    if ($max < $min) { return false; }
    // Find max & min length of the number
    $lenMin = strlen ($min);
    $lenMax = strlen ($max);

    // Generate a random length for the random number
    $randLen = $lenMin + mt_rand(0, $lenMax - $lenMin);
    /* Generate the random number digit by digit, 
       comparing it with the min and max values */
 $b_inRange = false;
    for ($i = 0; $i < $randLen; $i++)
 {
  $randDigit = mt_rand(0,9);

  /* As soon as we are sure that the number will stay 
          in range, we can stop comparing it to min and max */
  if (!$b_inRange)
  {
   $tempRand = $rand . $randDigit;
   $tempMin = substr($min, 0, $i+1);
   $tempMax = substr($max, 0, $i+1);
   // Make sure that the temporary random number is in range
   if ($tempRand < $tempMin || $tempRand > $tempMax)
   {
    $lastDigitMin = substr($tempMin, -1);
    $lastDigitMax = substr($tempMax, -1);
    $tempRand = $rand . @mt_rand($lastDigitMin, $lastDigitMax);
   }
   /* Check if $tempRand is equal to the min or to the max value. 
               If it is not equal, then we know it will stay in range */
   if ($tempRand > $tempMin && $tempRand < $tempMax)
   {
    $b_inRange = true;
   }
  }
  else
  {
   $tempRand = $rand . $randDigit;
  }
  $rand = $tempRand;  
 }
 return $rand;
}

I tried a couple times and it looks like it works OK. Optimize if needed. The idea is to start by figuring out a random length for your random number that would put it in the acceptable range. Then generate random digits one by one up to that length by concatenating. If it is not in range, generate a new random digit in range and concatenate.

我尝试过几次,看起来效果还可以。如果需要优化。我们的想法是首先确定随机数的随机长度,使其处于可接受的范围内。然后通过连接逐个生成随机数字到该长度。如果它不在范围内,则在范围内生成一个新的随机数并连接。

I use the fact that PHP will convert a string to a number to take advantage of the string functions. Of course this generates a warning for mt_rand, but as we use only numbers, it should be safe to suppress it.

我使用PHP将字符串转换为数字以利用字符串函数的事实。当然这会为mt_rand生成警告,但由于我们只使用数字,所以应该可以安全地抑制它。

Now, I have to say that I am quite curious as to why you need this in the first place.

现在,我不得不说,我很好奇为什么你首先需要这个。

#7


0  

/* Inputs: 
 * min - GMP number or string: lower bound
 * max - GMP number or string: upper bound
 * limiter - GMP number or string: how much randomness to use.
 *  this value is quite obscure (see `gmp_random`, but the default
 *  supplies several hundred bits of randomness, 
 *  which is probably enough.
 * Output: A random number between min (inclusive) and max (exclusive).
*/
function BigRandomNumber($min, $max, $limiter = 20) {
  $range = gmp_sub($max, $min);
  $random = gmp_random();
  $random = gmp_mod($random, $range);
  $random = gmp_add($min, $random);
  return $random;
}

This is just the classic formula rand_range($min, $max) = $min + rand() % ($max - $min) translated to arbitrary-precision arithmetic. It can exhibit a certain amount of bias if $max - $min isn't a power of two, but if the number of bits of randomness is high enough compared to the size of $max - $min the bias becomes negligible.

这只是经典公式rand_range($ min,$ max)= $ min + rand()%($ max - $ min)转换为任意精度算术。如果$ max - $ min不是2的幂,它可能会表现出一定的偏差,但如果随机性的位数与$ max - $ min的大小相比足够高,则偏差变得可以忽略不计。

#8


0  

This may work:

这可能有效:

  • Split the number into an array with 9 numbers or less ("the rest") ... 9 chars because max rand number is 2147483647 on my machine.
  • 将数字拆分为9个或更少的数字(“其余”)... 9个字符,因为我的机器上的最大兰特数是2147483647。

  • For each "9-or-less numbers array block", create a random number.
  • 对于每个“9或更少数字数组块”,创建一个随机数。

  • Implode the array and you will now have a usable random number.
  • 内爆数组,您现在将拥有一个可用的随机数。

Example code that illustrates the idea (notice: the code is undone)

示例代码说明了这个想法(注意:代码被撤消)

function BigRandomNumber($min,$max) {
// Notice: Will only work when both numbers have same length.
echo (strlen($min) !== strlen($max)) ? "Error: Min and Max numbers must have same length" : NULL;
$min_arr = str_split($min);
$max_arr = str_split($max);
// TODO: This loop needs to operate on 9 chars ($i will increment by $i+9)
for($i=0; $i<=count($max_arr); $i++) {
    if($i == 0) {
        // First number: >=first($min) and <=first($max).
        $new_arr[$i] = rand( $min_arr[0], $max_arr[0]);
    } else if($i == count($max_arr)) {
        // Last number <= $max .. not entirely correct, feel free to correct it.
        $new_arr[$i] = rand(0, substr($max,-1));
    } else {
        $new_arr[$i] = rand(0,9);
    }
}
return implode($new_arr);
}

#9


0  

Tested and works

经过测试和工作

<?php 

$min = "1225468798745475454898787465154";
$max = "1225468798745475454898787465200";

$bigRandNum = bigRandomNumber($min,$max);
echo "The Big Random Number is: ".$bigRandNum."<br />";

function bigRandomNumber($min,$max) {
    // take the max number length
    $number_length = strlen($max);

    // Set the counter
    $i = 1;

    // Find the base and the min and max ranges
    // Loop through the min to find the base number
    while ($i <= $number_length) {
        $sub_string = substr($min, 0, $i);

        // format pattern
        $format_pattern = '/'.$sub_string.'/';
        if (!preg_match($format_pattern, $max)) {
            $base = $sub_string;

            // Set the min and max ranges
            $minRange = substr($min, ($i - 1), $number_length);
            $maxRange = substr($max, ($i - 1), $number_length);

            // End while loop, we found the base
            $i = $number_length;
        }
        $i++;
    }
    // find a random number with the min and max range
    $rand = rand($minRange, $maxRange);

    // add the base number to the random number
    $randWithBase = $base.$rand;

    return $randWithBase;
}

?>

#10


0  

Generating 'n' random chars is not really an option, as random('9999999999') could still, theoretically, return 1...

生成'n'个随机字符实际上不是一个选项,因为随机('9999999999')理论上仍然可以返回1 ...

Here's a quite simple function:

这是一个非常简单的功能:

function bcrand($max) { 
    return bcmul($max, (string)mt_rand() / mt_getrandmax() ); 
}

Note that it will NOT return N bits of randomness, just adjust scale

请注意,它不会返回N位随机性,只需调整比例

#11


-1  

Take your floor and and your random number in the range to it.

把你的地板和随机数放在范围内。

1225468798745475454898787465154 + rand(0, 6)

#12


-1  

Here is pseudocode:

这是伪代码:


// generate a random number between N1 and N2

rangesize = N2 - N1 + 1
randlen = length(rangesize) + 4 // the 4 is to get more digits to reduce bias
temp = BigRandomNumber(randlen) // generate random number, "randlen" digits long
temp = temp mod rangesize
output N1 + temp

Notes:

  • all arithmetic here (except in the second line) must be arbitrary precision: use the bcmath library for this
  • 这里的所有算术(第二行除外)必须是任意精度:为此使用bcmath库

  • in the second line, "length" is number of digits, so the "length" of 1025 would be 4
  • 在第二行中,“length”是位数,因此1025的“length”将是4