Я пытался создать это, но на самом деле это не работает.
Вот таблица того, как я хочу, чтобы это работало .. нажмите, чтобы увидеть картинку
Вот изображение моей базы данных (в phpmyadmin) нажмите, чтобы увидеть картинку
Я хочу, чтобы он сначала посмотрел на проценты и нашел, какой из них использовать.
IE: 75% шанс получить случайное число от 1 до 50. 20% шанс получить случайное число от 51 до 200 и т. д.
Вот мой код:
if ($_GET['method'] == "test") {
$sql = "SELECT 1percentage, 1min, 1max, 2percentage, 2min, 2max, 3percentage, 3min, 3max, 4percentage, 4min, 4max FROM `keys`";
$result = $conn->query($sql);
while($row = $result->fetch_assoc()) {
$total = $row["1percentage"] + $row["2percentage"] + $row["3percentage"] + $row["4percentage"] + 1;
$random = rand(0, $total);
if ($random < $row['1percentage'] || $random == $row['1percentage']) {
$amount = rand($row['1min'], $row['1max']);
} elseif ($random > $row['1percentage'] && $random < $row['2percentage'] || $random == $row['2percentage']) {
$amount = rand($row['2min'], $row['2max']);
} elseif ($random > $row['2percentage'] && $random < $row['3percentage'] || $random == $row['3percentage']) {
$amount = rand($row['3min'], $row['3max']);
} elseif ($random > $row['4percentage'] || $random == $row['4percentage']) {
$amount = rand($row['4min'], $row['4max']);
} else {
exit("0");
}
echo $amount;
}
}
Но он выводит либо от 1 до 50, либо от 1001 до 10000.
Так что я сделал не так?
См .: Почему я должен предоставлять MCVE для того, что мне кажется очень простым запросом SQL?
@EugeneAnisiutkin Я изменил это, но он все равно дает те же результаты ..
@Strawberry, снимок экрана с таблицами, который я отправляю, взят из базы данных, использующей SELECT
, ничего плохого там нет ..
@ Просто еще один youtube - скриншот не MCVE, вам действительно стоит его создать. Кроме того, снимок экрана не является результатом вашего SQL-запроса, и, судя по снимку экрана, ваш SQL-запрос не работает.
Возможно, вы не читали связанный ответ. Извините, скриншоты не делаю - но развлекаюсь.
Также $row["1percentage"] + $row["2percentage"] + $row["3percentage"] + $row["4percentage"] + 1
выдаст результат 101
. Просто из любопытства - как у вас может быть 101% шанс получить случайное число? Более того: ваш алгоритм на 100% выдаст случайное число от 0 до 101 и вообще не принимает во внимание проценты счета.
Глядя на ваш код и значения в предоставленной вами записи базы данных, ваша текущая настройка не будет работать.
Во-первых, операторы if
должны быть очищены следующим образом:
if ($_GET['method'] == "test") {
$sql = "SELECT 1percentage, 1min, 1max, 2percentage, 2min, 2max, 3percentage, 3min, 3max, 4percentage, 4min, 4max FROM `keys`";
$result = $conn->query($sql);
while($row = $result->fetch_assoc()) {
$total = $row['1percentage'] + $row['2percentage'] + $row['3percentage'] + $row['4percentage'] + 1;
$random = rand(0, $total);
if ($random <= $row['1percentage']) {
$amount = rand($row['1min'], $row['1max']);
} elseif ($random > $row['1percentage'] && $random <= $row['2percentage']) {
$amount = rand($row['2min'], $row['2max']);
} elseif ($random > $row['2percentage'] && $random <= $row['3percentage']) {
$amount = rand($row['3min'], $row['3max']);
} elseif ($random >= $row['4percentage']) {
$amount = rand($row['4min'], $row['4max']);
} else {
exit("0");
}
echo $amount;
}
}
Это не только сделает сценарий более эффективным, но и сделает код более понятным и, надеюсь, более легким для отладки.
Во-вторых, для того, чтобы это работало правильно, вам нужно начать с вашего наименьшего процента в 1 процент и увеличивать оттуда, поскольку ваши условия используют диапазоны больше / меньше между этими значениями. Например, посмотрите на второе условие:
if ($random > $row['1percentage'] && $random <= $row['2percentage'])
На опубликованном вами скриншоте мы видим, что 1 процент (75) больше 2 процентов (20). Поскольку никакое число не может быть больше 75, а также меньше или равно 20, это условие никогда не будет выполнено. Условия 3 и 4 аналогичны. Следовательно, единственные два условия, которые могут быть выполнены, - это первое и последнее. При текущей настройке любое число, большее или равное 1 проценту (в данном случае 75), будет удовлетворять первому условию. Любое число меньше 1 процента и больше или равно 4 процента (в данном случае 1) будет удовлетворять последнему условию.
Либо измените порядок ваших процентов в порядке возрастания, либо перепишите условия и сделайте выборочную проверку, чтобы убедиться, что вы получаете желаемое поведение.
Другой возможный подход ...
Как предположил @Eugene Anisiutkin, сам алгоритм требует доработки. Если предположить, что его следующее утверждение верно ...
«Задача - сгенерировать случайные числа от 1 до 50 с вероятностью генерации 75%, от 51 до 200 с вероятностью генерации 20%, от 201 до 1000 с вероятностью генерации 4% и от 1001 до 10000 с вероятностью генерации. 1% ".
... тогда вам нужно будет сгенерировать 75 случайных чисел из диапазона 1-50, 20 случайных чисел из диапазона 51-200, 4 случайных чисел из диапазона 201-1000 и 1 случайное число из диапазона 1001-10000. Сохранив все случайно сгенерированные числа в массиве, вы можете затем сгенерировать окончательное случайное число между 0 и последним индексом этого массива (count($randArray)-1
). Это случайное число будет индексом числа, которое вы хотите использовать из массива. Имейте в виду, что «процентные» значения будут истинными процентами, только если они в сумме будут равны 100. В противном случае вы можете рассматривать их больше как «вес». При таком подходе не требуется, чтобы «процентное» число располагалось в каком-либо порядке. Код будет выглядеть примерно так:
if ($_GET['method'] == "test") {
$sql = "SELECT 1percentage, 1min, 1max, 2percentage, 2min, 2max, 3percentage, 3min, 3max, 4percentage, 4min, 4max FROM `keys`";
$result = $conn->query($sql);
while($row = $result->fetch_assoc()) {
//store the record values for easy reference
$p1 = $row['1percentage'];
$p1min = $row['1min'];
$p1max = $row['1max'];
$p2 = $row['2percentage'];
$p2min = $row['2min'];
$p2max = $row['2max'];
$p3 = $row['3percentage'];
$p3min = $row['3min'];
$p3max = $row['3max'];
$p4 = $row['4percentage'];
$p4min = $row['4min'];
$p4max = $row['4max'];
$randomArray = array();
for($i = 0; $i < $p1; $i++){
$newRandom = rand($p1min, $p1max); //generate appropriate random number
array_push($randomArray, $newRandom); //add the random number to the array
}
for($i = 0; $i < $p2; $i++){
$newRandom = rand($p2min, $p2max); //generate appropriate random number
array_push($randomArray, $newRandom); //add the random number to the array
}
for($i = 0; $ i < $p3; $i++){
$newRandom = rand($p3min, $p3max); //generate appropriate random number
array_push($randomArray, $newRandom); //add the random number to the array
}
for($i=0;$i<$p4;$i++){
$newRandom = rand($p4min, $p4max); //generate appropriate random number
array_push($randomArray, $newRandom); //add the random number to the array
}
//get last index of array
$uBound = count($randomArray)-1;
//get a random index
$randomIndex = rand(0, $uBound);
$amount = $randomArray[$randomIndex];
echo $amount;
}
}
Он все равно не будет работать должным образом, сам алгоритм неправильный. $total = $row['1percentage'] + $row['2percentage'] + $row['3percentage'] + $row['4percentage'] + 1
дает вам 101, а $random = rand(0, $total);
дает случайное значение от 0 до 101, и это значение не имеет ничего общего с восприятием.
@EugeneAnisiutkin, я согласен, не зная больше о том, чего они пытаются достичь, текущий алгоритм не имеет смысла. Мой ответ был просто лучшей попыткой объяснить, почему они видят, что в любом случае выполняется только одно из двух условий. Надеюсь, что как только первоначальная проблема будет решена, она либо послужит их конкретной цели, либо они смогут легче пересмотреть алгоритм.
Мне довольно ясно, чего они пытаются достичь. Задача - сгенерировать случайные числа от 1 до 50 с вероятностью генерации 75%, от 51 до 200 с вероятностью генерации 20%, от 201 до 1000 с вероятностью генерации 4% и от 1001 до 10000 с вероятностью генерации 1. %. Это непростая задача, потому что вероятностная часть имеет смысл только тогда, когда вы генерируете не менее 100 чисел, а лучше 1000.
Потратив некоторое время на решение этой проблемы, я пришел к несколько другому решению. Реализация вероятностей в этом примере плохая, но она показывает основной пример достижения необходимой вероятности практически для любого количества сгенерированных данных. Приведенный ниже код не будет работать правильно, если вы установите переменную $how_much_numbers_to_generate
ниже как минимум 50, но это вполне вероятно. Набор данных должен быть довольно большим, чтобы получить точную вероятность. Также, чтобы пример работал, вы должны заменить имя пользователя, пароль и базу данных в $mysqli = new mysqli("localhost", "my_name", "my_pass", "my_database");
на те, которые вы используете. Полный код ниже
<?php
$mysqli = new mysqli("localhost", "my_username", "my_password", "my_database");
if ($mysqli->connect_errno) {
printf("Connect failed: %s\n", $mysqli->connect_error);
exit();
}
$how_much_numbers_to_generate = 1000;
$result = $mysqli->query("SELECT 1percentage, 1min, 1max, 2percentage, 2min, 2max, 3percentage, 3min, 3max, 4percentage, 4min, 4max FROM percentages");
while($row = $result->fetch_assoc())
{
$first_percentage = $row['1percentage'];
$first_min = $row['1min'];
$first_max = $row['1max'];
$second_percentage = $row['2percentage'];
$second_min = $row['2min'];
$second_max = $row['2max'];
$third_percentage = $row['3percentage'];
$third_min = $row['3min'];
$third_max = $row['3max'];
$fourth_percentage = $row['4percentage'];
$fourth_min = $row['4min'];
$fourth_max = $row['4max'];
$first_numbers_generated=0;
$second_numbers_generated=0;
$third_numbers_generated=0;
$fourth_numbers_generated=0;
$random_array = array();
for($numbers_generated=0; $numbers_generated < $how_much_numbers_to_generate; $numbers_generated++)
{
if ( $first_numbers_generated==0 || $first_numbers_generated/$numbers_generated * 100.0 <= $first_percentage)
{
$random_value = rand($first_min, $first_max);
$first_numbers_generated++;
}
else if ( $second_numbers_generated==0 || $second_numbers_generated/$numbers_generated * 100.0 <= $second_percentage)
{
$random_value = rand($second_min, $second_max);
$second_numbers_generated++;
}
else if ( $third_numbers_generated==0 || $third_numbers_generated/$numbers_generated * 100.0 <= $third_percentage)
{
$random_value = rand($third_min, $third_max);
$third_numbers_generated++;
}
else if ( $fourth_numbers_generated==0 || $fourth_numbers_generated/$numbers_generated * 100.0 <= $fourth_percentage)
{
$random_value = rand($fourth_min, $fourth_max);
$fourth_numbers_generated++;
}
else
{
$random_value = rand($first_min, $fourth_max);
if ($random_value <= $first_max)
{
$first_numbers_generated++;
}
else if ($random_value <= $second_max)
{
$second_numbers_generated++;
}
else if ($random_value <= $third_max)
{
$third_numbers_generated++;
}
else
{
$fourth_numbers_generated++;
}
}
array_push($random_array, $random_value);
}
echo "First numbers generated: " . $first_numbers_generated . "<br/>";
echo "Second numbers generated: " . $second_numbers_generated . "<br/>";
echo "Third numbers generated: " . $third_numbers_generated . "<br/>";
echo "Fourth numbers generated: " . $fourth_numbers_generated . "<br/>";
echo "First probability: " . ($first_numbers_generated/$numbers_generated * 100.0) . "<br/>";
echo "Second probability: " . ($second_numbers_generated/$numbers_generated * 100.0) . "<br/>";
echo "Third probability: " . ($third_numbers_generated/$numbers_generated * 100.0) . "<br/>";
echo "Fourth probability: " . ($fourth_numbers_generated/$numbers_generated * 100.0) . "<br/>";
}
Это интересная проблема, и я думаю, что она была решена раньше.
Функция Python random.choices
решает очень похожую проблему.
Вот попытка преобразовать это в PHP в соответствии с текущим вариантом использования.
# https://github.com/python/cpython/blob/master/Lib/bisect.py#L22
function bisect(array $a, float $x, int $lo, int $hi): int {
$mid = $lo + $hi;
while ($lo < $hi) {
$mid = ($lo + $hi) / 2;
if ($x < $a[$mid]) {
$hi = $mid;
} else {
$lo = $mid + 1;
}
}
return $lo;
}
/*
* Generate a random number
* from 1 to 50, with the generation probability 75%,
* from 51 to 200 with the generation probability 20%,
* from 201 to 1000 with the generation probability 4% and
* from 1001 to 10000 with the generation probability 1%.
*/
function randomChoice(array $population, array $weights): int
{
$cummWeights = array_reduce($weights, function ($acc, $curr) {
$lastSlice = array_slice($acc, -1);
$acc[] = $lastSlice[0] + $curr;
return $acc;
}, [0]);
# remove 0 starting value
array_shift($cummWeights);
$lastWeightSlice = array_slice($cummWeights, -1);
$total = $lastWeightSlice[0];
$probability = ((float)rand() / (float)getrandmax());
$needle = $probability * $total;
# look for $needle in $cummWeights, then use that to select which population distribution to generate a random number from.
# https://github.com/python/cpython/blob/master/Lib/random.py#L387
$index = bisect($cummWeights, $needle, 0, count($population));
$distribution = $population[$index];
return rand($distribution[0], $distribution[1]);
}
echo randomChoice(
[
[51, 200],
[1, 50],
[201, 1000],
[1001, 10000]
],
[20, 75, 4, 1]
);
Вау, гораздо лучшее решение. Я подумал о том, чтобы нарисовать нечто похожее на бумаге, а затем кодировать его, но, к сожалению, у меня не было времени.
Я бы использовал
$random <= $row['1percentage']
вместо$random < $row['1percentage'] || $random == $row['1percentage']
. Так будет легче найти проблему.