共计 2874 个字符,预计需要花费 8 分钟才能阅读完成。
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));
正文完