2009-09-25 21 views
12

Busco una forma de generar un gran número aleatoriocon PHP, algo así como:En PHP, ¿cómo puedo generar un gran número pseudoaleatorio?

mt_rand($lower, $upper); 

Cuanto más cerca que he visto es gmp_random() sin embargo no me permite especificar el los límites inferior y superior solo el número de bits por miembro (que no tengo idea de qué se trata).

EDIT: Axsuuls la respuesta parece ser muy cercana a lo que quiero y muy similar a gmp_random, sin embargo, parece que hay un solo error en un escenario.

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

y:

Así que si el fu nción se llama BigRandomNumber():

BigRandomNumber($length = 31); 

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

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

BigRandomNumber('1225468798745475454898787465154', '1225468798745475454898787465200'); 

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

Para la referencia, creo que la solución podría tener que hacer uso de function supplied in this question.

EDIT: El post anterior fue suprimido, 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; 
    } 
} 
+2

¿Usted está buscando un número aleatorio o una cadena de dígitos al azar? .. ¿Qué planifica utilizar el resultado de esta llamada de función? si los valores que desea son> PHP_INT_MAX, manipularlos se convierte en un problema. –

+0

Su último enlace ("función proporcionada en esta pregunta") está roto. – robguinness

+1

@robguinness: Se ha solucionado. –

Respuesta

15

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

+0

Con su enfoque, solo habrá unos 100 millones de posibilidades. –

+0

Así que aumente la precisión a 16. Realmente, es la única forma efectiva de generar 1 número aleatorio y luego "escalarlo" al rango apropiado. No soy un estadístico. –

+1

Quiere decir bcdiv (mt_rand(), mt_getrandmax(), 8); ¿derecho? –

1

Lo que puede hacer es crear un par de números aleatorios pequeños y combinarlos. Sin embargo, no estoy seguro de lo grande que realmente necesita.

+0

Tuve la misma idea, aunque no estoy seguro de cuán aleatorio sería el número generado. –

+0

Sería casi tan aleatorio como los números aleatorios más pequeños. – mob

+1

Sí, es casi tan aleatorio, el problema principal es que ninguno de los números comenzará con cero. Entonces, los ceros serán menos comunes en algunos casos raros. –

2

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 comenzar su número al azar gigante con un 0? Si no, que también puede ser implementado 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!

+0

Puede convertir a int al final para deshacerse de cualquier amonut de ceros a la izquierda. –

+0

@Vinko, si asigna el número aleatorio a un int, obtendrá el número en notación científica. –

+0

@Axsuul: Este es un buen enfoque, sin embargo, quiero especificar el límite superior e inferior de los números en lugar del número de longitud ¿cómo lo haría? –

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

:-) totalmente no probado

-1

Tome su piso y su número y aleatorio en el rango a ella.

1225468798745475454898787465154 + rand(0, 6) 
+0

Eso se desbordará seguro. –

-1

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 bcmath para este
  • en la segunda línea, "longitud" es el número de dígitos, por lo que la "longitud" de 1025 sería 4
+0

BigRandomNumber() es la función que falta. Además, supones que el tamaño de la gama será menor que el límite superior de BigRandomNumber(). Esa suposición podría no funcionar si el generador aleatorio de BigRandomNumber() es mt_rand(), y si no lo es, entonces tiene que escribirlo, de lo que se trata esta pregunta. – Sylverdrag

+0

La función 'BigRandomNumber' en mi respuesta se refiere a la respuesta de Axsuul. –

5

Lo que realmente necesita saber es la brecha relativa; si es pequeño, entonces puedes generar un número de 0 a la brecha máxima y luego agregar el mínimo a eso.

+0

Esta es la respuesta más brillante aquí. – Shoe

0

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 calcular una longitud aleatoria para su número aleatorio que lo pondría en el rango aceptable. Luego genere dígitos aleatorios uno por uno hasta esa longitud mediante concatenación. Si no está dentro del rango, genera un nuevo dígito aleatorio en el rango y concatenar.

Utilizo el hecho de que PHP convertirá una cadena en un número para aprovechar las funciones de cadena. Por supuesto, esto genera una advertencia para mt_rand, pero como usamos solo números, debería ser seguro suprimirlo.

Ahora, tengo que decir que tengo bastante curiosidad sobre por qué necesita esto en primer lugar.

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

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

0

Esto puede funcionar:

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

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

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

?> 
0

Generación 'n' caracteres aleatorios no es realmente una opción, ya random ('9999999999') aún podría, teóricamente, devolver 1 ...

Aquí hay una función bastante simple:

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

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

Cuestiones relacionadas