2

なぜ分散は確率の結果によってランダムに十分に大きいのですか?

テストコード:

function probability($chances) {

    asort($chances);
    $sum    = array_sum($chances);
    $random = mt_rand(1, $sum);

    foreach($chances as $key => $chance) {
        if($random < $chance)
            return $key;
    }

    return $key;

}

$chances['case1'] = 10;
$chances['case2'] = 30;
$chances['case3'] = 60;

$result = array();

for($i = 0; $i < 100000; $i++)
    @$result[probability($chances)]++;

asort($result);
$sum = array_sum($result);

echo "Case\tCount\tOrig\tResult\n";

foreach($result as $key => $value)
    echo "$key\t$value\t".$chances[$key]."%\t".round($value / $sum * 100)."%\n";

結果:

Case    Count   Orig    Result
case1   14913   10%     15%
case2   33099   30%     33%
Case3   51988   60%     52%

なんとか調整できますか?使用しようとしましたmt_srand()が、役に立ちません。

情報:

$ php -v
PHP 5.3.10-1ubuntu3.2 with Suhosin-Patch (cli) (built: Jun 13 2012 17:20:55) 
Copyright (c) 1997-2012 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2012 Zend Technologies
    with Xdebug v2.1.0, Copyright (c) 2002-2010, by Derick Rethans
    with Suhosin v0.9.33, Copyright (c) 2007-2012, by SektionEins GmbH

$ uname -a
Linux desktop 3.2.0-26-generic-pae #41-Ubuntu SMP Thu Jun 14 16:45:14 UTC 2012 i686 i686 i386 GNU/Linux
4

3 に答える 3

2

乱数の生成に欠陥があります。

まず、asort通話を削除することを検討してください。それは何の役にも立たず、混乱を招きます(そして遅いです)。配列を100000回ソートしています!配列がソートされるという前提条件を追加する(そしてループの前に一度ソートする)か、ソートが不要なアルゴリズムを実装することをお勧めします。

次に、各ケースにヒットする確率がすべてのケースで正しいことを確認する必要があります。これらは今あなたの確率です:

case1: 10 % (1 <= $random <= 10)
case2: 20 % (11 <= $random <= 30)
case3: 70 % (everything that didn't match previous cases)

あなたが本当にする必要があるのはこのようなものです:

function probability($chances) {
    $sum    = array_sum($chances);
    $random = mt_rand(1, $sum);

    $add = 0;
    foreach($chances as $key => $chance) {
        if($random <= $chance + $add)
            return $key;
        else
            $add += $chance;
    }

    return $key;
}

これにより、期待される結果が得られます。

case1: 10 % (1 <= $random <= 10)
case2: 30 % (11 <= $random <= 40)
case3: 60 % (41 <= $random <= 100)
于 2012-06-28T06:27:29.377 に答える
1
$sum    = max($chances);

max()array_sum()合計しないでください、 instedを使用してください

私はこの結果を得ました:

Case    Count   Orig    Result
case1   11068   10%     11%
case2   29672   30%     30%
case3   59260   60%     59%

このバージョンのコードを実行すると、次のようになります。

<?php

function probability($chances)
{
    asort($chances);
    $sum    = array_sum($chances);
    $random = mt_rand(1, $sum);

    foreach($chances as $key => $chance)
    {
        $random -= $chance;
        if($random <= 0)
        {
            return $key;
        }
    }

    return $key;
}

$chances['case1'] = 10;
$chances['case2'] = 30;
$chances['case3'] = 60;

$result = array();

for($i = 0; $i < 100000; $i++)
{
    @$result[probability($chances)]++;
}

asort($result);
$sum = array_sum($result);

echo "Case\tCount\tOrig\tResult\n";

foreach($result as $key => $value)
{
    echo "$key\t$value\t".$chances[$key]."%\t".round($value / $sum * 100)."%\n";
}
?>
于 2012-06-28T06:07:00.063 に答える
1

まず、内部の比較probabilityは間違っています。そうであるべきであり、そうでは<=ありません<

これにより、少なくとも結果の一貫性が向上するはずです(つまり、10、20、70)

次に、case3が二重にカウントされます(nr <= 60の場合、およびnr> 60の場合)。

コードにこの変更を加えることを提案します。

function probability($chances)
{
    $sum    = array_sum($chances);
    $random = mt_rand(1, $sum);

    foreach($chances as $key => $chance) {
        if ($random <= $chance) {
            return $key;
        }
    }

    return 'rest';
}

$chances次に、配列に「rest」を追加します。これはソートされた順序で表示される必要があります。

$chances['case1'] = 10;
$chances['case2'] = 30;
$chances['case3'] = 60;
$chances['rest'] = 'NA'; // for 60 < x <= 100

結果:

Case    Count   Orig    Result
case1   10083   10%     10%
case2   19965   30%     20%
case3   30084   60%     30%
rest    39868   NA%     40%
于 2012-06-28T06:39:40.923 に答える