2009-09-25 25 views
12

Sto cercando un modo per generare un gran numero dicasuali con PHP, qualcosa di simile a:In PHP, come faccio a generare un grande numero pseudo-casuale?

mt_rand($lower, $upper); 

Il più vicino che ho visto è gmp_random() tuttavia non mi permette di specificare il i limiti inferiore e superiore solo il numero di bit per arto (che non ho idea di cosa sia).

MODIFICA: la risposta di Axsuuls sembra essere molto simile a quello che voglio e molto simile a gmp_random tuttavia sembra che ci sia solo un difetto in uno scenario.

Supponiamo che io wan't per ottenere un numero casuale tra:

e:

Quindi, se il fu nction si chiama BigRandomNumber():

BigRandomNumber($length = 31); 

Questo può facilmente tornare 9999999999999999999999999999999 che è fuori dei limiti regolamentari.

Come posso utilizzare un limite minimo/massimo anziché un valore di lunghezza?

BigRandomNumber('1225468798745475454898787465154', '1225468798745475454898787465200'); 

Ciò dovrebbe restituire un numero casuale tra 1225468798745475454898787465 [154 .. 200].

Per il riferimento, credo che la soluzione potrebbe dover utilizzare il function supplied in this question.

EDIT: Il post di cui sopra è stato eliminato, eccolo:

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

Siete alla ricerca di un numero casuale o una stringa di cifre casuali? .. Cosa pensi di utilizzare per il risultato di questa chiamata di funzione? se i valori che desideri sono> PHP_INT_MAX, manipolarlo diventa un problema .. –

+0

Il tuo ultimo collegamento ("la funzione fornita in questa domanda") è rotto. – robguinness

+1

@robguinness: risolto. –

risposta

15

provare:

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 matematica è come segue: moltiplicare la differenza tra il minimo e il massimo di una percentuale casuale, e aggiungere al minimo (con arrotondamento in int).

+0

Con il tuo approccio, ci saranno solo circa 100 milioni di possibilità. –

+0

Aumenta quindi la precisione a 16. In realtà, è l'unico modo efficace per generare 1 numero casuale e quindi "ridimensionarlo" nell'intervallo corretto. Non sono uno statistico. –

+1

Si intende bcdiv (mt_rand(), mt_getrandmax(), 8); destra? –

1

Che cosa si può fare è creare un paio di numeri casuali più piccoli e combinarle. Non sono sicuro di quanto sia effettivamente necessario.

+0

Ho avuto la stessa idea, non sono sicuro di quanto sia casuale il numero generato. –

+0

Sarebbe quasi casuale come i numeri casuali più piccoli. – mob

+1

Sì, è quasi casuale, il problema principale è che nessuno dei numeri inizierà con zero. Quindi gli zeri saranno meno comuni in alcuni rari casi. –

2

Questo vi darà più zeri nel vostro numero a caso gigante e si può anche specificare la lunghezza del numero casuale gigante (può il vostro numero a caso gigante iniziare con uno 0? Se no, che può anche essere facilmente implementato)

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

?> 

Buona fortuna!

+0

Puoi lanciare a int alla fine per sbarazzarti di qualsiasi amonut degli zeri a sinistra. –

+0

@Vinko, se lanci il numero casuale su un int, otterrai il numero in notazione scientifica. –

+0

@Axsuul: Questo è un buon approccio, tuttavia, voglio specificare il limite superiore e inferiore dei numeri anziché la lunghezza del numero come farei? –

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 non testato :-)

-1

Prendete il vostro piano e ed il vostro numero a caso nella gamma ad esso.

1225468798745475454898787465154 + rand(0, 6) 
+0

Questo avrà un overflow di sicuro. –

-1

Ecco pseudocodice:


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

Note:

  • tutta l'aritmetica qui (tranne che nella seconda riga) deve essere di precisione arbitraria: utilizzare la libreria bcmath per questo
  • nella seconda riga, "lunghezza" è il numero di cifre, quindi la "lunghezza" di 1025 sarebbe 4
+0

BigRandomNumber() è la funzione mancante. Inoltre, si assume che il range sarà inferiore al limite superiore del BigRandomNumber(). Questa ipotesi potrebbe non funzionare se il generatore casuale di BigRandomNumber() è mt_rand(), e se non lo è, allora devi scriverlo, che è di che cosa si tratta. – Sylverdrag

+0

La funzione 'BigRandomNumber' nella mia risposta si riferisce alla risposta di Axsuul. –

5

Quello che devi veramente sapere è il divario relativo; se è piccolo, puoi generare un numero compreso tra 0 e l'intervallo massimo, quindi aggiungere il minimo a tale valore.

+0

Questa è la risposta più brillante qui. – Shoe

0

Questo potrebbe funzionare per voi. (Io non sono sicuro perché ne hai bisogno, quindi potrebbe non essere il modo migliore per farlo, ma dovrebbe soddisfare le vostre esigenze):

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

Ho provato un paio di volte e sembra che funziona bene. Ottimizza se necessario. L'idea è iniziare calcolando una lunghezza casuale per il tuo numero casuale che lo inserisca nell'intervallo accettabile. Quindi genera le cifre casuali una alla volta fino a quella lunghezza concatenando. Se non è compreso nell'intervallo, genera una nuova cifra casuale nell'intervallo e concatena.

Uso il fatto che PHP convertirà una stringa in un numero per sfruttare le funzioni stringa. Ovviamente questo genera un avvertimento per mt_rand, ma siccome usiamo solo numeri, dovrebbe essere sicuro di sopprimerlo.

Ora, devo dire che sono abbastanza curioso sul motivo per cui è necessario questo in primo luogo.

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

Questo è solo la formula classica rand_range($min, $max) = $min + rand() % ($max - $min) tradotto all'aritmetica precisione arbitraria. Può mostrare una certa dose di bias se $max - $min non è una potenza di due, ma se il numero di bit di casualità è abbastanza elevato rispetto alla dimensione di $max - $min, il bias diventa trascurabile.

0

Questo può funzionare:

  • Spalato il numero in una matrice con 9 numeri o meno ("il resto") ... 9 chars perché il numero massimo di rand è 2147483647 sulla mia macchina.
  • Per ogni "9-or-less numbers array block", creare un numero casuale.
  • Implodete la matrice e avrete ora un numero casuale utilizzabile.
codice

esempio che illustra l'idea (avviso: il codice è annullata)

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

testato e funziona

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

Generazione 'n' caratteri casuali non è davvero un'opzione, come casuale ('9999999999') potrebbe ancora, teoricamente, restituire 1 ...

Ecco una semplice funzione:

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

notare che non tornerà N bit di casualità, basta regolare scala