function canReward( $rate) {
$mt_rand = mt_rand();
$last = mt_getrandmax();
return $mt_rand / $last <= $rate;
}
function getRandomVal( $min, $max) {
// Random random = new round(0,);
// return random.nextInt($max - $min + 1) + min;
return mt_rand(0,$max - $min + 1) + $min;
}
function getRandomValWithSpecifySubRate( $boundMin, $boundMax, $subMin, $subMax, $subRate) {
if (canReward($subRate)) {
return getRandomVal($subMin, $subMax);
}
return getRandomVal($boundMin, $boundMax);
}
/**
* 随机分配第n个红包
* @param $totalBonus 总红包量
* @param $totalNum 总份数
* @param $sendedBonus 已发送红包量
* @param $sendedNum 已发送份数
* @param $rdMin 随机下限
* @param $rdMax 随机上限
* @return
*/
function randomBonusWithSpecifyBound($totalBonus, $totalNum, $sendedBonus,
$sendedNum, $rdMin, $rdMax, $bigRate) {
$avg = $totalBonus / $totalNum; // 平均值
$leftLen = $avg - $rdMin;
$rightLen = $rdMax - $avg;
$boundMin = 0;
$boundMax = 0;
// 大范围设置小概率
if ($leftLen === $rightLen) {
$boundMin = max(($totalBonus - $sendedBonus - ($totalNum - $sendedNum - 1) * $rdMax), $rdMin);
$boundMax = min(($totalBonus - $sendedBonus - ($totalNum - $sendedNum - 1) * $rdMin), $rdMax);
} else if (ord($leftLen) > 0) {
// 上限偏离
$standardRdMax = $avg + $leftLen; // 右侧对称上限点
$rdMax = canReward($bigRate) ? $rdMax : $standardRdMax;
$boundMin = max(($totalBonus - $sendedBonus - ($totalNum - $sendedNum - 1) * $standardRdMax), $rdMin);
$boundMax = min(($totalBonus - $sendedBonus - ($totalNum - $sendedNum - 1) * $rdMin), $rdMax);
} else {
// 下限偏离
$standardRdMin = $avg - $rightLen; // 左侧对称下限点
$rdMin = canReward($bigRate) ? $rdMin : $standardRdMin;
$boundMin = max(($totalBonus - $sendedBonus - ($totalNum - $sendedNum - 1) * $rdMax), $rdMin);
$boundMax = min(($totalBonus - $sendedBonus - ($totalNum - $sendedNum - 1) * $standardRdMin), $rdMax);
}
// 已发平均值偏移修正-动态比例
if ($boundMin === $boundMax) {
return getRandomVal($boundMin, $boundMax);
}
$currAvg = $sendedNum == 0 ? $avg : ($sendedBonus / $sendedNum); // 当前已发平均值
$middle = ($boundMin + $boundMax) / 2.0;
$subMin = $boundMin ;
$subMax = $boundMax;
// 期望值
$exp = $avg - ($currAvg - $avg) * $sendedNum / ($totalNum - $sendedNum);
if ($middle > $exp) {
$subMax = (int) round(($boundMin + $exp) / 2.0);
} else {
$subMin = (int) round(($exp + $boundMax) / 2.0);
}
$expBound = ($boundMin + $boundMax) / 2;
$expSub = ($subMin + $subMax) / 2;
$subRate = ($exp - $expBound) / ($expSub - $expBound);
return getRandomValWithSpecifySubRate($boundMin, $boundMax, $subMin, $subMax, $subRate);
}
/**
* 从java 移值 微信红包算法
*/
function getRand2( $totalBonus, $totalNum, $rdMin, $rdMax, $bigRate) {
$sendedBonus = 0;
$sendedNum = 0;
$bonusList = [];
while ($sendedNum < $totalNum) {
$bonus = randomBonusWithSpecifyBound($totalBonus, $totalNum, $sendedBonus, $sendedNum, $rdMin, $rdMax, $bigRate);
$bonusList[] = (int) $bonus;
$sendedNum++;
$sendedBonus += $bonus;
}
if(array_sum($bonusList) > $totalBonus)
$bonusList[array_search(max($bonusList),$bonusList)] = $bonusList[array_search(max($bonusList),$bonusList)] - (array_sum($bonusList) - $totalBonus);
elseif(array_sum($bonusList) < $totalBonus)
$bonusList[array_search(min($bonusList),$bonusList)] = $bonusList[array_search(min($bonusList),$bonusList)] + ($totalBonus - array_sum($bonusList) );
return $bonusList;
}
$arr = getRand2(5300, 80, 50, 400, 0.8);
var_dump($arr);
var_dump(array_sum($arr));
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。