Pregunta

Estoy buscando una manera de generar una grande de números aleatorios con PHP, algo como:

mt_rand($lower, $upper);

Cuanto más cerca que he visto es gmp_random ( ) sin embargo, no permite mí especificar los límites inferior y superior sólo el número de bits por las extremidades (que no tengo idea de lo que es).

EDIT: Axsuuls respuesta parece ser bastante cerca de lo que quiero y muy similar a gmp_random sin embargo parece que hay sólo una falla en uno de los escenarios

.

Supongamos que wa no para obtener un número aleatorio entre:

  • 1225468798745475454898787465154

y

  • 1225468798745475454898787465200

Así que si la función se llama BigRandomNumber ():

BigRandomNumber($length = 31);

Esto puede volver fácilmente 9999999999999999999999999999999 que está fuera de los límites especificados.

¿Cómo puedo utilizar un mínimo / máximo límite en lugar de un valor de longitud?

BigRandomNumber('1225468798745475454898787465154', '1225468798745475454898787465200');

Esto debería devolver un número aleatorio entre 1225468798745475454898787465 [154 .. 200] .

En la referencia creo que la solución podría tener que hacer uso de la función suministrada en esta pregunta .

EDIT: Se ha eliminado el post anterior, aquí está:

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;
  }
}
¿Fue útil?

Solución

Pruebe lo siguiente:

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);
}

La matemática es la siguiente:. Multiplicar la diferencia entre el mínimo y máximo en un porcentaje aleatorio, y añadir a la mínima (con redondeo a un int)

Otros consejos

Lo que realmente necesita saber es la diferencia relativa; si es pequeño, entonces se puede generar un número del 0 al máximo la brecha a continuación, añadir el mínimo para ello.

Esto le dará más ceros en su número al azar gigante y también se puede especificar la longitud del número aleatorio gigante (puede su número al azar gigante comenzar con un 0? Si no, que también se puede implementar fácilmente)

<?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;

?>

Buena suerte!

Lo que puede hacer es crear un par de números aleatorios pequeños y combinarlos. No está seguro de qué tan grande que realmente necesita sin embargo.

$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);

Totalmente probado: -)

Esto podría funcionar para usted. (No estoy seguro de por qué lo necesita, por lo que podría no ser la mejor manera de hacerlo, pero debe adaptarse a sus necesidades):

<?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;
}

He intentado un par de veces y parece que funciona bien. Optimizar si es necesario. La idea es comenzar por averiguar una longitud al azar para su número al azar que lo pondría en un rango aceptable. Luego generar una dígitos al azar por uno hasta que la longitud mediante la concatenación. Si no está dentro del rango, generar un nuevo dígito al azar dentro del alcance y concatenar.

Yo uso el hecho de que PHP convertir una cadena en un número de aprovechar las funciones de cadena. Por supuesto, esto genera una advertencia de mt_rand, pero a medida que usamos sólo números, debe ser seguro para suprimirla.

Ahora, tengo que decir que estoy bastante curioso en cuanto a por qué necesita esto en primer lugar.

/* 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;
}

Esto es sólo el rand_range($min, $max) = $min + rand() % ($max - $min) fórmula clásica traducido a la aritmética de precisión arbitraria. Se puede mostrar una cierta cantidad de sesgo si $max - $min no es una potencia de dos, pero si el número de bits de aleatoriedad es lo suficientemente alta en comparación con el tamaño de $max - $min el sesgo se hace despreciable.

Esto puede funcionar:

  • Dividir el número en una matriz con los números 9 o menos ( "el resto") ... 9 caracteres porque el número máximo de rand es 2147483647 en mi máquina.
  • Para cada "9 o menos números de bloque de matriz", crear un número aleatorio.
  • Implode la matriz y que ahora tendrá un número aleatorio utilizable.

código de ejemplo que ilustra la idea (Aviso: el código se deshace)

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);
}

probado y funciona

<?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;
}

?>

Generación 'n' caracteres aleatorios no es realmente una opción, como al azar ( '9999999999') podría todavía, teóricamente, volver 1 ...

Esto es una función bastante simple:

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

Tenga en cuenta que no volverá N bits de aleatoriedad, simplemente ajustar la escala

Tome su suelo y su número y aleatorio en el rango a él.

1225468798745475454898787465154 + rand(0, 6)

Aquí es pseudocódigo:


// 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

Notas:

  • toda la aritmética aquí (excepto en la segunda línea) debe ser de precisión arbitraria: utilizar la biblioteca para este bcmath
  • en la segunda línea, "longitud" es el número de dígitos, por lo que la "longitud" de 1025 sería 4
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top