2009-10-19 7 views
2

J'ai un simple morceau de code PHP qui nécessite la création d'un nombre aléatoire. Cependant, même si l'entrée est toujours positive, elle renvoie parfois une sortie négative.Pourquoi rand() retournerait-il une valeur négative lorsque les valeurs min et max sont positives?

Voici mon code de débogage:

$debt = rand($this->gdp * 0.02, $this->gdp * 0.17); 
echo "<p>GDP: ".$this->gdp." rand(".$this->gdp * 0.02." , ".$this->gdp * 0.17.") = <strong>".$debt."</strong></p>"; 

Voici un exemple de sortie:

GDP: 219254674605 rand(4385093492.1 , 37273294682.85) = 75276999 

GDP: 345015694865 rand(6900313897.3 , 58652668127.05) = -1636353016 

GDP: 90445390920 rand(1808907818.4 , 15375716456.4) = -165604705 

GDP: 3412849650 rand(68256993 , 580184440.5) = 347516196 

GDP: 2939111315 rand(58782226.3 , 499648923.55) = 119181875 

GDP: 26369065 rand(527381.3 , 4482741.05) = 3632416 

GDP: 215838135 rand(4316762.7 , 36692482.95) = 28784811 

GDP: 511763530 rand(10235270.6 , 86999800.1) = 39954394 

GDP: 42416245 rand(848324.9 , 7210761.65) = 3974882 

GDP: 75090235 rand(1501804.7 , 12765339.95) = 5201966 

Alors, pourquoi un rand() de deux nombres positifs donner un rendement négatif?

Toute aide serait grandement appréciée! Parce que vous voyez un débordement d'entier dans les arguments.

Répondre

14

Selon le rand() documentation, il prend deux valeurs int comme arguments. Sur une machine 32 bits, ce sont aussi des 32 bits (au moins pour PHP). Donc, lorsque vous passez des arguments plus grands que 2 − 1 ils débordent et commencent à à nouveau.

Apparemment, si vous avez besoin de plus grandes valeurs, vous devrez le coder vous-même. Alors que la simple création d'un nombre de 64 bits à partir de deux nombres de 32 bits fonctionne comme prévu, vous ne pouvez pas simplement faire une opération modulo avec votre valeur maximale car cela fausse la distribution. Pour une bonne implémentation comment générer un entier aléatoire uniformément distribué entre 0 et une certaine limite supérieure, vous pouvez jeter un oeil à java.util.Random.nextInt(int) et adapter en conséquence pour les entiers de 64 bits.

mt_rand() alors qu'habituellement un bon choix pour les nombres aléatoires parce qu'il utilise MT19937 au lieu d'un mauvais LCG, n'aide pas non plus ici car ses arguments sont aussi int s.


Une autre option que vous pouvez envisager si vous ne souhaitez pas toutes les valeurs possibles à prélever éventuellement:

  • Générer une valeur aléatoire à virgule flottante compris entre 0 et 1 en appelant

    $rnd = mt_rand()/(double)mt_getrandmax() 
    
  • Déterminer la gamme des nombres dont vous avez besoin:

    $min = $this->gdp * 0.02; 
    $max = $this->gdp * 0.17; 
    $range = $max - $min; 
    
  • multiplier par la valeur aléatoire à virgule flottante précédemment obtenue et ajouter le minimum:

    $value = $min + $range * $rnd 
    
  • Maintenant vous avez une valeur aléatoire entre vos limites choisies. Il est approximativement distribué uniformément, bien qu'il y ait des pas discrets entre les nombres aléatoires adjacents puisque vous étirez 32 bits d'aléatoire sur un plus grand nombre de bits. Si ce n'est pas un problème pour vous, allez-y, cependant.

+1

Pensez à utiliser mt_rand() à la place – Psytronic

+1

Psytronic: qui change * quoi * exactement? http://de.php.net/manual/en/function.mt-rand.php montre que 'mt_rand' utilise aussi les arguments' int'. – Joey

+0

J'allais juste sur la note sous la description de rand: Remarque: Sur certaines plateformes (comme Windows), getrandmax() est seulement 32768. Si vous avez besoin d'une plage plus grande que 32768, spécifier min et max vous permettra de créez une plage plus grande que celle-ci, ou envisagez d'utiliser mt_rand() à la place. – Psytronic

1

Rand prend comme arguments, et les rendements, integers. Les entiers (en PHP) ont généralement une portée maximale de 2 ** 32.

Vos arguments doubles sont plus grands, provoquant integer overflow lorsqu'ils sont convertis en nombres entiers.

Questions connexes