Попытка получить случайное число с шансом получить это число

Я пытался создать это, но на самом деле это не работает.

Вот таблица того, как я хочу, чтобы это работало .. нажмите, чтобы увидеть картинку

Вот изображение моей базы данных (в 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.

Так что я сделал не так?

Я бы использовал $random <= $row['1percentage'] вместо $random < $row['1percentage'] || $random == $row['1percentage']. Так будет легче найти проблему.

Eugene Anisiutkin 30.10.2018 13:35

@EugeneAnisiutkin Я изменил это, но он все равно дает те же результаты ..

Just another youtuber 30.10.2018 13:38

@Strawberry, снимок экрана с таблицами, который я отправляю, взят из базы данных, использующей SELECT, ничего плохого там нет ..

Just another youtuber 30.10.2018 13:40

@ Просто еще один youtube - скриншот не MCVE, вам действительно стоит его создать. Кроме того, снимок экрана не является результатом вашего SQL-запроса, и, судя по снимку экрана, ваш SQL-запрос не работает.

Eugene Anisiutkin 30.10.2018 13:42

Возможно, вы не читали связанный ответ. Извините, скриншоты не делаю - но развлекаюсь.

Strawberry 30.10.2018 13:44

Также $row["1percentage"] + $row["2percentage"] + $row["3percentage"] + $row["4percentage"] + 1 выдаст результат 101. Просто из любопытства - как у вас может быть 101% шанс получить случайное число? Более того: ваш алгоритм на 100% выдаст случайное число от 0 до 101 и вообще не принимает во внимание проценты счета.

Eugene Anisiutkin 30.10.2018 13:57
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
2
7
85
3

Ответы 3

Глядя на ваш код и значения в предоставленной вами записи базы данных, ваша текущая настройка не будет работать.

Во-первых, операторы 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, и это значение не имеет ничего общего с восприятием.

Eugene Anisiutkin 30.10.2018 14:04

@EugeneAnisiutkin, я согласен, не зная больше о том, чего они пытаются достичь, текущий алгоритм не имеет смысла. Мой ответ был просто лучшей попыткой объяснить, почему они видят, что в любом случае выполняется только одно из двух условий. Надеюсь, что как только первоначальная проблема будет решена, она либо послужит их конкретной цели, либо они смогут легче пересмотреть алгоритм.

Justin T. 30.10.2018 14:11

Мне довольно ясно, чего они пытаются достичь. Задача - сгенерировать случайные числа от 1 до 50 с вероятностью генерации 75%, от 51 до 200 с вероятностью генерации 20%, от 201 до 1000 с вероятностью генерации 4% и от 1001 до 10000 с вероятностью генерации 1. %. Это непростая задача, потому что вероятностная часть имеет смысл только тогда, когда вы генерируете не менее 100 чисел, а лучше 1000.

Eugene Anisiutkin 30.10.2018 14:18

Потратив некоторое время на решение этой проблемы, я пришел к несколько другому решению. Реализация вероятностей в этом примере плохая, но она показывает основной пример достижения необходимой вероятности практически для любого количества сгенерированных данных. Приведенный ниже код не будет работать правильно, если вы установите переменную $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]
);

Вау, гораздо лучшее решение. Я подумал о том, чтобы нарисовать нечто похожее на бумаге, а затем кодировать его, но, к сожалению, у меня не было времени.

Eugene Anisiutkin 31.10.2018 08:45

Другие вопросы по теме