Question

Je suis à la recherche d'un moyen de générer un grand nombre aléatoire avec PHP, quelque chose comme:

mt_rand($lower, $upper);

Plus j'ai vu est gmp_random ( ) mais il ne me permet pas de préciser les limites inférieures et supérieures seulement le nombre de bits par membre (que je ne sais pas ce qu'il est).

EDIT: Axsuuls réponse semble être assez proche de ce que je veux et très semblable à gmp_random mais il semble y avoir qu'un seul défaut dans un scénario

.

Supposons que je wan't pour obtenir un nombre aléatoire entre:

  • 1225468798745475454898787465154

et

  • 1225468798745475454898787465200

Donc, si la fonction est appelée BigRandomNumber ():

BigRandomNumber($length = 31);

Cela peut facilement revenir 9999999999999999999999999999999 qui est hors de la limite spécifiée.

Comment puis-je utiliser un min / max limite au lieu d'une valeur de longueur?

BigRandomNumber('1225468798745475454898787465154', '1225468798745475454898787465200');

Cela devrait retourner un nombre aléatoire entre 1225468798745475454898787465 [154 .. 200] .

Pour la référence, je crois que la solution pourrait être amenée à utiliser la fonction fournie dans cette question.

EDIT: Le message ci-dessus a été supprimé, la voici:

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;
  }
}
Était-ce utile?

La solution

Effectuez les opérations suivantes:

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

Le calcul est comme suit:. Multiplier la différence entre le minimum et le maximum d'un pourcentage aléatoire, et ajouter au minimum (avec arrondi à un entier)

Autres conseils

Qu'est-ce que vous avez vraiment besoin de savoir est l'écart relatif; si elle est petite, vous pouvez alors générer un nombre de 0 à l'écart maximal ajouter le minimum à cela.

Cela vous donnera plus de zéros dans votre nombre aléatoire géant et vous pouvez également spécifier la longueur du nombre aléatoire géant (peut votre nombre aléatoire géant commencer par un 0? Sinon, cela peut aussi être facilement mis en œuvre)

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

?>

Bonne chance!

Ce que vous pouvez faire est de créer quelques petits nombres aléatoires et les combiner. Vous ne savez pas sur la taille que vous avez réellement besoin bien.

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

totalement non testé: -)

Cela pourrait fonctionner pour vous. (Je ne sais pas pourquoi vous en avez besoin, il pourrait ne pas être la meilleure façon de le faire, mais il devrait répondre à vos besoins):

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

J'ai essayé deux fois et il semble que cela fonctionne correctement. Optimiser au besoin. L'idée est de commencer par déterminer une longueur aléatoire pour votre nombre aléatoire qui placerait dans la fourchette acceptable. Ensuite, générer un chiffres au hasard par un jusqu'à cette longueur par concaténer. Si elle est hors de portée, générer un nouveau chiffre aléatoire dans la gamme et concaténer.

J'utilise le fait que PHP convertit une chaîne en nombre pour tirer parti des fonctions de chaîne. Bien sûr, cela génère un avertissement pour mt_rand, mais comme nous utilisons des chiffres, il doit être sûr de le supprimer.

Maintenant, je dois dire que je suis tout à fait curieux de savoir pourquoi vous avez besoin ce en premier lieu.

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

Ceci est juste la formule classique rand_range($min, $max) = $min + rand() % ($max - $min) traduit à l'arithmétique de précision arbitraire. Il peut présenter une certaine quantité de parti pris si $max - $min n'est pas une puissance de deux, mais si le nombre de bits de caractère aléatoire est assez élevé par rapport à la taille de $max - $min le biais devient négligeable.

Cela peut fonctionner:

  • Split le numéro dans un tableau avec 9 chiffres ou moins ( "le reste") ... 9 caractères, car le nombre de rand max est 2147483647 sur ma machine.
  • Pour chaque « 9 ou moins les numéros de blocs de tableau », créer un nombre aléatoire.
  • Implode le tableau et vous avez maintenant un nombre aléatoire utilisable.

Exemple de code qui illustre l'idée (Remarque: le code est annulée)

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

testé et fonctionne

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

?>

Génération 'n' est pas au hasard caractères vraiment une option, comme aléatoire ( '9999999999') pourrait encore, en théorie, revenir 1 ...

Voici une fonction simple:

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

Notez qu'il ne sera pas de retour N bits de hasard, juste régler l'échelle

Prenez votre sol et votre numéro et aléatoire dans la plage à elle.

1225468798745475454898787465154 + rand(0, 6)

Voici 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:

  • toutes les opérations arithmétiques ici (sauf dans la deuxième ligne) doit être une précision arbitraire: utiliser la bibliothèque bcmath pour cette
  • dans la deuxième ligne, « longueur » est le nombre de chiffres, de sorte que la « longueur » de 1025 serait 4
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top