В PHP, как я могу создать большой псевдо-случайных чисел?
Я ищу способ генерировать большое случайное число с помощью PHP, что-то вроде:
mt_rand($lower, $upper);
Чем ближе я видел, тем gmp_random () однако он не позволяет мне указывать нижнюю и верхнюю границы только количество битов на Лимб (что я понятия не имею, что это такое).
EDIT: Axsuuls ответ, кажется, довольно близок к тому, что я хочу и очень похож на gmp_random, однако, кажется, есть только один недостаток в одном сценарии.
Предположим, что я не хочу чтобы получить случайное число между:
- 1225468798745475454898787465154
И:
- 1225468798745475454898787465200
Таким образом, если функция называется BigRandomNumber():
BigRandomNumber($length = 31);
Это может легко вернуть 99999999999999999999999999999, который находится вне указанной границы.
Как я могу использовать границу min / max вместо значения длины?
BigRandomNumber('1225468798745475454898787465154', '1225468798745475454898787465200');
Это должно возвращать случайное число между 1225468798745475454898787465 [154 .. 200] .
Для справки я полагаю, что решение, возможно, придется использовать функцию , поставленную в этом вопросе.
EDIT: вышеуказанный пост был удален, вот он:
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;
}
}
12 ответов:
Попробуйте следующее:
Математика выглядит следующим образом: умножьте разницу между минимумом и максимумом на случайный процент и добавьте к минимуму (с округлением до int).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); }
Что вам действительно нужно знать, так это относительный зазор; если он мал, то вы можете сгенерировать число от 0 до максимального зазора, а затем добавить к нему минимальный.
Это даст вам больше нулей в вашем гигантском случайном числе, и вы также можете указать длину гигантского случайного числа (может ли ваше гигантское случайное число начинаться с 0? если нет, то это также может быть легко реализовано)
<?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; ?>
Удачи!
Что вы можете сделать, так это создать несколько случайных чисел меньшего размера и объединить их. Хотя не уверен, насколько большой вам на самом деле нужен.
$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);
Полностью непроверено : -)
Это может сработать для вас. (Я не уверен, зачем вам это нужно, так что это может быть не лучший способ сделать это, но он должен соответствовать вашим требованиям):
<?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; }
Я пробовал пару раз, и, похоже, это работает нормально. Оптимизируйте, если это необходимо. Идея состоит в том, чтобы начать с определения случайной длины для вашего случайного числа, которое поместило бы его в приемлемый диапазон. Затем генерируйте случайные цифры одну за другой до этой длины путем объединения. Если он не находится в диапазоне, сгенерируйте новую случайную цифру в диапазоне и связывать.
Я использую тот факт, что PHP преобразует строку в число, чтобы воспользоваться преимуществами строковых функций. Конечно, это генерирует предупреждение для mt_rand, но поскольку мы используем только числа, его следует безопасно подавить.
Теперь я должен сказать, что мне очень любопытно, зачем вам это нужно в первую очередь.
Это всего лишь классическая формула/* 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; }
rand_range($min, $max) = $min + rand() % ($max - $min)
, переведенная в арифметику произвольной точности. Он может проявлять некоторое смещение, если$max - $min
не является степенью двойки, но если число битов случайности достаточно велико по сравнению с размером$max - $min
, смещение становится незначительным.
Это может сработать:
- разбейте число на массив с числом 9 или меньше ("остальные")... 9 символов, потому что Макс Рэнд номер 2147483647 на моей машине.
- для каждого блока массива "9 или менее чисел" создайте случайное число.
- взорвите массив, и теперь у вас будет полезное случайное число.
Пример кода, иллюстрирующего идею (обратите внимание: код отменен)
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); }
Испытано и работает
<?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; } ?>
Генерация ' N ' случайных символов на самом деле не является вариантом, поскольку random('9999999999') все еще теоретически может вернуть 1...
Вот довольно простая функция:
function bcrand($max) { return bcmul($max, (string)mt_rand() / mt_getrandmax() ); }
Обратите внимание, что он не вернет N бит случайности, просто отрегулируйте масштаб
Возьмите свой этаж и свое случайное число в диапазоне до него.
1225468798745475454898787465154 + rand(0, 6)
Вот псевдокод:
// 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
Примечания:
- вся арифметика здесь (кроме второй строки) должна быть произвольной точности: используйте библиотеку bcmath для этого
- во второй строке "длина" - это число цифр, поэтому "длина" 1025 будет равна 4