3
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));

missonce
96 声望5 粉丝

php 菜鸟