給定隨機數的取值範圍(最小值、最大值),且要求屢次取得的隨機數最後的結果有一個固定的平均值。算法
算法以下: 測試
1 /****** 2 * author ztg 281099678 2018-12-06 3 * @param $min float 範圍最小值 4 * @param $max float 範圍最大值 5 * @param $avg float 最後的平均數 6 * @return float 結果隨機數 7 */ 8 function avg_rand($min, $max, $avg) { 9 $maxAvg = ($max + $avg) / 2; // 取得大區間的平均數 10 $minAvg = ($min + $avg) / 2; // 取得小區間的平均數 11 12 if ($maxAvg - $avg == 0) { 13 return $max; 14 } 15 if ($avg - $minAvg == 0) { 16 return $min; 17 } 18 $multiple = ($avg - $minAvg) / ($maxAvg - $avg); //小區間的平均數與平均數的差距,是大區間與平均數的差距的多少倍? 19 20 /*** 爲了更精確獲得隨機數,下面的取值,都*100 ***/ 21 $baseArea = 1000; //區間的基礎範圍是多少(隨意設定,稍微大點更精確)? 22 $rMax = $baseArea + $multiple * $baseArea; //規劃區間範圍,在基礎範圍內加另外多餘倍數的區間 23 24 $r = rand(0, $rMax); //區間隨機取一個值 25 26 //打印測試 27 echo 'maxAvg:' . $maxAvg . ' -- minAvg:' . $minAvg . ' -- min:' . $min . ' -- max:' . $max . ' -- avg:' . $avg . ' -- rMax:' . $rMax . ' -- multiple:' . $multiple . ' -- r:' . $r ;echo "\n"; 28 //若是隨機值在大區間內,則爲小數額;不然爲大數額 29 if ($r > $multiple * $baseArea) { 30 $i = rand($min * 100, $avg * 100) / 100; 31 } else { 32 $i = rand($avg * 100 + 1, $max * 100 ) / 100; 33 } 34 35 return $i; 36 } 37 38 //測試 39 $res = $resMax = $resMin = []; 40 for ($i = 0; $i < 1000; $i ++) { 41 $min = 1; 42 $avg = 9.2; 43 $avg = 2.2; 44 // $avg = 6; 45 // $avg = 1; 46 // $avg = 11; 47 $max = 11; 48 $re = avg_rand($min, $max, $avg); 49 $res[] = $re; 50 if ($re < $avg) { 51 $resMin[] = $re; 52 } else { 53 $resMax[] = $re; 54 } 55 } 56 57 echo "\n"; 58 echo "\n"; 59 echo 'avg:' . $avg . "\n\n"; 60 echo 'result:'.( array_sum($res) / count($res)) . ' -- sum:' . array_sum($res) . ' -- count:' . count($res) ; 61 echo "\n"; 62 echo "max -- avg:";echo ($max + $avg) / 2; echo ' -- count:'; print_r(count($resMax)); echo ' -- resultAvg:' . (array_sum($resMax) / count($resMax)); 63 echo "\n"; 64 echo 'min -- avg:' ; echo ($avg + $min) / 2; echo ' -- count:'; print_r(count($resMin)); echo ' -- resultAvg:' . (count($resMin) ? (array_sum($resMin) / count($resMin)) : 0); 65 echo "\nresMin:";print_r($resMin); 66 echo "\nresMax:";print_r($resMax); 67 echo "\nres:";print_r($res); 68 69 exit;