【问题标题】:Trying to get a random number with a chance to get that number试图获得一个随机数并有机会获得该数字
【发布时间】:2018-10-30 12:15:26
【问题描述】:

我试图创建它,但它并没有真正起作用。

这是我希望它如何工作的表格。 click to see picture

这是我的数据库图片(在 phpmyadmin 中)click to see picture

我希望它首先查看百分比,然后找到要使用的百分比。

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

但它输出的是 or 1 到 50,或 1001 到 10000。

那么我做错了什么?

【问题讨论】:

  • 我会使用$random &lt;= $row['1percentage'] 而不是$random &lt; $row['1percentage'] || $random == $row['1percentage']。这样会更容易找到问题。
  • @EugeneAnisiutkin 我改变了它,但它仍然提供相同的输出..
  • @Strawberry 我发送的表格屏幕截图来自使用SELECT 的数据库中没有任何问题..
  • @只是另一个 youtube - 截图不是 MCVE,你真的应该创建一个。此外,屏幕截图不是您的 SQL 查询的结果,从屏幕截图判断您的 SQL 查询失败。

标签: php mysql random


【解决方案1】:

查看您提供的代码和数据库记录中的值,您当前的设置将不起作用。

首先,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;
    }

}

这不仅会提高脚本的效率,还会使代码更易于理解,并有望更容易调试。

其次,要使其正常工作,您需要从 1percentage 中的最小百分比开始并从那里增加,因为您的条件使用这些值之间的大于/小于范围。例如,看第二个条件:

if ($random > $row['1percentage'] && $random <= $row['2percentage'])

在您发布的屏幕截图中,我们看到 1percentage (75) 大于 2percentage (20)。由于没有数字可以大于 75 并且小于或等于 20,因此永远不会满足此条件。条件 3 和 4 类似。因此,唯一可能满足的两个条件是第一个和最后一个。根据当前的设置,任何大于或等于 1%(在本例中为 75)的数字都将满足第一个条件。任何小于 1% 且大于或等于 4%(在本例中为 1)的数字都将满足最后一个条件。

要么按升序重新排列您的百分比,要么重写您的条件,并进行一些抽查以确保您获得了所需的行为。

另一种可能的方法...

正如@Eugene Anisiutkin 所建议的,算法本身需要一些改造。假设他的以下陈述是正确的......

"任务是生成随机数从 1 到 50,生成概率为 75%,从 51 到 200,生成概率为 20%,从 201 到 1000,生成概率为 4%,从 1001到 10000,生成概率为 1%。”

...那么您需要从 1-50 生成 75 个随机数,从 51-200 生成 20 个随机数,从 201-1000 生成 4 个随机数,以及从 1001-10000 生成 1 个随机数。将所有随机生成的数字存储在一个数组中后,您可以生成一个介于 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 个。
【解决方案2】:

这是一个有趣的问题,我认为它以前已经解决了。

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

【讨论】:

  • 哇,一个更好的解决方案。我想过在纸上画一个有点类似的解决方案,然后编写代码,但不幸的是我没有时间。
【解决方案3】:

在这个问题上花了一些时间后,我想出了一个稍微不同的解决方案。该示例中概率的实现很糟糕,但它确实显示了为几乎任何数量的生成数据实现所需概率的基本示例。如果您将$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/>";
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-14
    • 2015-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-22
    • 2011-12-26
    相关资源
    最近更新 更多