2009-09-25 13 views
12

szukam sposób do wygenerowania duży liczbę losową z PHP, coś takiego:W PHP, w jaki sposób mogę wygenerować dużą liczbę pseudolosową?

mt_rand($lower, $upper); 

Im bliżej Widziałem to gmp_random() jednak nie pozwala mi określić dolna i górna granica tylko liczba bitów na kończynę (której nie mam pojęcia, co to jest).

EDYCJA: Odpowiedź Axsuuls wydaje się być bardzo zbliżona do tego, czego chcę i bardzo podobna do gmp_random, jednak wydaje się, że w jednym scenariuszu występuje tylko jedna usterka.

Przypuśćmy wa, aby uzyskać liczbę losową między:

oraz:

Więc jeśli fu nction nazywa BigRandomNumber():

BigRandomNumber($length = 31); 

ten może łatwo powrócić 9999999999999999999999999999999 która jest w określonej granicy.

Jak mogę użyć granicy minimum/maksimum zamiast wartości długości?

BigRandomNumber('1225468798745475454898787465154', '1225468798745475454898787465200'); 

Należy zwrócić liczby losowej o wartości pomiędzy 1225468798745475454898787465 154 .. [200].

Dla odniesienia uważam, że rozwiązanie może wymagać użycia function supplied in this question.

EDIT: Powyższy post został usunięty, to jest tutaj:

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

Szukasz liczbę losową lub losowo cyfr ciąg? .. Do czego zamierzasz wykorzystać wynik tej funkcji? jeżeli wartości, które chcesz, to> PHP_INT_MAX, to manipulowanie nimi staje się problemem .. –

+0

Twój ostatni link ("funkcja podana w tym pytaniu") jest zepsuty. – robguinness

+1

@robguinness: Naprawiono. –

Odpowiedz

15

Spróbuj:

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

Math jest następujący: mnożenie różnicy pomiędzy minimalną i maksymalną losowym procent i dodać do minimum (w zaokrągleniu do int).

+0

Przy twoim podejściu będzie tylko około 100 milionów możliwości. –

+0

Więc zwiększ dokładność do 16. Naprawdę, jest to jedyny skuteczny sposób na wygenerowanie 1 liczby losowej, a następnie "skalowanie" jej do odpowiedniego zakresu. Nie jestem statystykiem. –

+1

Masz na myśli bcdiv (mt_rand(), mt_getrandmax(), 8); dobrze? –

1

Co można zrobić, to utworzyć kilka mniejszych liczb losowych i połączyć je. Nie jestem pewien, ile naprawdę potrzebujesz.

+0

Miałem ten sam pomysł, nie jestem pewny, jak losowa będzie generowana liczba. –

+0

Byłoby prawie tak samo losowe jak mniejsze liczby losowe. – mob

+1

Tak, to prawie tak przypadkowe, głównym problemem jest to, że żadna z liczb nie zacznie się od zera. Więc zera będą rzadsze w rzadkich przypadkach. –

2

To daje więcej zer na swoim ogromnym liczb losowych można także określić długość olbrzymiej liczby losowej (można uruchomić gigant liczb losowych z 0? Jeśli nie, to może być łatwo wdrożone)

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

?> 

Powodzenia!

+0

Możesz rzucić do int na końcu, aby pozbyć się amosu z lewych zer. –

+0

@ Vinko, jeśli rzucisz losową liczbę na int, otrzymasz numer w notacji naukowej. –

+0

@Asuf: To jest jednak dobre podejście, chcę określić górną i dolną granicę liczb, a nie długość numeru, jak to zrobić? –

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

Całkowicie niesprawdzone :-)

-1

Weź podłogę i oraz numer losową w przedziale do niego.

1225468798745475454898787465154 + rand(0, 6) 
+0

To na pewno się przepełni. –

-1

Oto pseudokod:


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

Uwagi:

  • wszystko arytmetyka tutaj (z wyjątkiem drugiej linii) musi być arbitralna precyzja: korzystania z biblioteki bcmath tego
  • w drugim wierszu "długość" to liczba cyfr, więc "długość" 1025 to 4
+0

BigRandomNumber() to funkcja, której brakuje. Zakładamy także, że zakres będzie mniejszy niż górny limit metody BigRandomNumber(). To założenie może nie działać, jeśli generator losowy BigRandomNumber() to mt_rand(), a jeśli nie, to musisz go napisać, o to właśnie chodzi. – Sylverdrag

+0

Funkcja "BigRandomNumber" w mojej odpowiedzi odnosi się do odpowiedzi Axsuula. –

5

To, co naprawdę musisz wiedzieć, to względna luka; jeśli jest mały, możesz wygenerować liczbę od 0 do maksymalnej luki, a następnie dodać do tego minimum.

+0

To jest najbardziej błyskotliwa odpowiedź tutaj. – Shoe

0

To może działać dla Ciebie. (Nie jestem pewien, dlaczego jest to potrzebne, więc to nie może być najlepszym sposobem, aby to zrobić, ale powinien dopasować swoje wymagania):

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

próbowałem kilka razy i wygląda na to, że działa OK. Zoptymalizuj w razie potrzeby. Chodzi o to, aby zacząć od znalezienia losowej długości dla losowej liczby, która pozwoliłaby na osiągnięcie akceptowalnego zakresu. Następnie generuj losowe cyfry jedna po drugiej do tej długości, łącząc się. Jeśli nie znajduje się w zasięgu, wygeneruj nową losową cyfrę w zakresie i połącz.

Używam faktu, że PHP konwertuje ciąg znaków na liczbę, aby skorzystać z funkcji napisów. Oczywiście generuje to ostrzeżenie dla mt_rand, ale ponieważ używamy tylko liczb, powinno być bezpiecznie tłumić to.

Teraz muszę powiedzieć, że jestem bardzo ciekawy, dlaczego tego potrzebujesz.

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

To jest właśnie klasyczny wzór rand_range($min, $max) = $min + rand() % ($max - $min) tłumaczona na duże liczby całkowite. Może wykazywać pewną dozę błędu, jeśli $max - $min nie jest potęgą dwóch, ale jeśli liczba bitów o losowości jest wystarczająco wysoka w porównaniu do rozmiaru $max - $min, odchylenie staje się nieistotne.

0

to może działać:

  • Podział liczby do tablicy z 9 cyfr lub mniej („reszty”) ... 9 znaków, ponieważ maksymalna liczba Rand 2147483647 na moim komputerze.
  • Dla każdego "bloku tablicy liczb 9 lub mniej" utwórz losową liczbę.
  • Implode macierz, a otrzymasz teraz użyteczną liczbę losową.

Przykładowy kod, który ilustruje ideę (uwaga: kod jest anulowany)

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

Przetestowane i działa

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

Generowanie 'n' losowych znaków nie jest to opcja, jak losowy ('9999999999') może teoretycznie powrócić 1 ...

Oto dość prosta funkcja:

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

pamiętać, że to NIE powrócić N bitów przypadkowości, tylko dostosować skalę

Powiązane problemy