1. 程式人生 > >【原創】給定隨機數的取值範圍(最小值、最大值),且要求多次取得的隨機數最後的結果有一個固定的平均值

【原創】給定隨機數的取值範圍(最小值、最大值),且要求多次取得的隨機數最後的結果有一個固定的平均值

給定隨機數的取值範圍(最小值、最大值),且要求多次取得的隨機數最後的結果有一個固定的平均值。

演算法如下:

/******
* author ztg 281099678 2018-12-06
* @param    $min    float   範圍最小值
* @param    $max    float   範圍最大值
* @param    $avg    float   最後的平均數
* @return float 結果隨機數
*/
function avg_rand($min, $max, $avg) {
    $maxAvg = ($max + $avg) / 2; //
取得大區間的平均數 $minAvg = ($min + $avg) / 2; // 取得小區間的平均數 if ($maxAvg - $avg == 0) { return $max; } if ($avg - $minAvg == 0) { return $min; } $multiple = ($avg - $minAvg) / ($maxAvg - $avg); //小區間的平均數與平均數的差距,是大區間與平均數的差距的多少倍? /*** 為了更精確得到隨機數,下面的取值,都*100 ***/ $baseArea
= 1000; //區間的基礎範圍是多少(隨意設定,稍微大點更精確)? $rMax = $baseArea + $multiple * $baseArea; //規劃區間範圍,在基礎範圍內加另外多餘倍數的區間 $r = rand(0, $rMax); //區間隨機取一個值 //列印測試 echo 'maxAvg:' . $maxAvg . ' -- minAvg:' . $minAvg . ' -- r:' . $r . ' -- multiple:' . $multiple . ' -- min:' . $min . ' -- avg:' . $avg ;echo "\n";
//如果隨機值在大區間內,則為小數額;否則為大數額 if ($r > $multiple * $baseArea) { $i = rand($min * 100, $avg * 100) / 100; } else { $i = rand($avg * 100 + 1, $max * 100 ) / 100; } return $i; } //測試 $res = $resMax = $resMin = []; for ($i = 0; $i < 1000; $i ++) { $min = 1; $avg = 9.2; // $avg = 2.2; // $avg = 6; $avg = 1; // $avg = 11; $max = 11; $re = avg_rand($min, $max, $avg); $res[] = $re; if ($re < $avg) { $resMin[] = $re; } else { $resMax[] = $re; } } echo "\n"; echo "\n"; echo 'avg:' . $avg . "\n\n"; echo 'result:'.( array_sum($res) / count($res)) . ' -- sum:' . array_sum($res) . ' -- count:' . count($res) ; echo "\n"; echo 'min -- avg:' ; echo ($avg + $min) / 2; echo ' -- count:'; print_r(count($resMin)); echo ' -- resultAvg:' . (array_sum($resMin) / count($resMin)); echo "\nmax -- avg:";echo ($max + $avg) / 2; echo ' -- count:'; print_r(count($resMax)); echo ' -- resultAvg:' . (array_sum($resMax) / count($resMax)); echo "\nresMin:";print_r($resMin); echo "\nresMax:";print_r($resMax); print_r($res); exit;