亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 邏輯算法 > 正文

PHP 生成隨機紅包算法

2020-03-22 16:20:11
字體:
來源:轉載
供稿:網友

基本思路

在隨機數生成方面,我借鑒了這位博主 @悲慘的大爺 的思路:

原文:比如要把 1 個紅包分給 N 個人,實際上就是相當于要得到 N 個百分比數據 條件是這 N 個百分比之和 = 100/100。這 N 個百分比的平均值是 1/N。 并且這 N 個百分比數據符合一種正態分布(多數值比較靠近平均值)。

解讀:比如我有 1000 塊錢,發 50 個紅包,就先隨機出 50 個數,然后算出這 50 個數的均值 avg,用 avg/(1/N),就得到了一個基數 mixrand ,然后用隨機出的那 50 個數分別去除以 mixrand ,得到每個數相對基數的百分比 randVal ,然后用 randVal 乘以 1000 塊錢,就可以得到每個紅包的具體金額了。

算法實現

Talk is cheap, show me your code!

核心生成算法:

<?php/* * Note: 紅包生成隨機算法 */html' target='_blank'>class Reward{    public $rewardMoney;        // 紅包金額、單位元    public $rewardNum;          // 紅包數量    // 執行紅包生成算法    public function splitReward($rewardMoney, $rewardNum, $max, $min)    {        // 傳入紅包金額和數量,因為小數在計算過程中會出現很大誤差,所以我們直接把金額放大100倍,后面的計算全部用整數進行        $min = $min * 100;        $max = $max * 100;        // 預留出一部分錢作為誤差補償,保證每個紅包至少有一個最小值        $this->rewardMoney = $rewardMoney * 100 - $rewardNum * $min;        $this->rewardNum = $rewardNum;        // 計算出發出紅包的平均概率值、精確到小數4位。        $avgRand = 1 / $this->rewardNum;        $randArr = [];        // 定義生成的數據總合sum        $sum = 0;        $t_count = 0;        while ($t_count < $rewardNum) {            // 隨機產出四個區間的額度            $c = rand(1, 100);            if ($c < 15) {                $t = round(sqrt(mt_rand(1, 1500)));            } else if ($c < 65) {                $t = round(sqrt(mt_rand(1500, 6500)));            } else if ($c < 95) {                $t = round(sqrt(mt_rand(6500, 9500)));            } else {                $t = round(sqrt(mt_rand(9500, 10000)));            }            ++$t_count;            $sum += $t;            $randArr[] = $t;        }        // 計算當前生成的隨機數的平均值,保留4位小數        $randAll = round($sum / $rewardNum, 4);        // 為將生成的隨機數的平均值變成我們要的1/N,計算一下每個隨機數要除以的總基數mixrand。此處可以約等處理,產生的誤差后邊會找齊        // 總基數 = 均值/平均概率        $mixrand = round($randAll / $avgRand, 4);        // 對每一個隨機數進行處理,并乘以總金額數來得出這個紅包的金額。        $rewardArr = array();        foreach ($randArr as $key => $randVal) {            // 單個紅包所占比例randVal            $randVal = round($randVal / $mixrand, 4);            // 算出單個紅包金額            $single = floor($this->rewardMoney * $randVal);            // 小于最小值直接給最小值            if ($single < $min) {                $single += $min;            }            // 大于最大值直接給最大值            if ($single > $max) {                $single = $max;            }            // 將紅包放入結果數組            $rewardArr[] = $single;        }        // 對比紅包總數的差異、將差值放在第一個紅包上        $rewardAll = array_sum($rewardArr);        // 此處應使用真正的總金額rewardMoney,$rewardArr[0]可能小于0        $rewardArr[0] = $rewardMoney * 100 - ($rewardAll - $rewardArr[0]);        // 第一個紅包小于0時,做修正        if ($rewardArr[0] < 0) {            rsort($rewardArr);            $this->add($rewardArr, $min);        }        rsort($rewardArr);        // 隨機生成的最大值大于指定最大值        if ($rewardArr[0] > $max) {            // 差額            $diff = 0;            foreach ($rewardArr as $k => &$v) {                if ($v > $max) {                    $diff += $v - $max;                    $v = $max;                } else {                    break;                }            }            $transfer = round($diff / ($this->rewardNum - $k + 1));            $this->diff($diff, $rewardArr, $max, $min, $transfer, $k);        }        return $rewardArr;    }    // 處理所有超過最大值的紅包    public function diff($diff, &$rewardArr, $max, $min, $transfer, $k)    {        // 將多余的錢均攤給小于最大值的紅包        for ($i = $k; $i < $this->rewardNum; $i++) {            // 造隨機值            if ($transfer > $min * 20) {                $aa = rand($min, $min * 20);                if ($i % 2) {                    $transfer += $aa;                } else {                    $transfer -= $aa;                }            }            if ($rewardArr[$i] + $transfer > $max) continue;            if ($diff - $transfer < 0) {                $rewardArr[$i] += $diff;                $diff = 0;                break;            }            $rewardArr[$i] += $transfer;            $diff -= $transfer;        }        if ($diff > 0) {            $i++;            $this->diff($diff, $rewardArr, $max, $min, $transfer, $k);        }    }    // 第一個紅包小于0,從大紅包上往下減    public function add(&$rewardArr, $min)    {        foreach ($rewardArr as &$re) {            $dev = floor($re / $min);            if ($dev > 2) {                $transfer = $min * floor($dev / 2);                $re -= $transfer;                $rewardArr[$this->rewardNum - 1] += $transfer;            } elseif ($dev == 2) {                $re -= $min;                $rewardArr[$this->rewardNum - 1] += $min;            } else {                break;            }        }        if ($rewardArr[$this->rewardNum - 1] > $min || $rewardArr[$this->rewardNum - 1] == $min) {            return;        } else {            $this->add($rewardArr, $min);        }    }}

細節考慮

下邊這段代碼用來控制具體的業務邏輯,按照具體的需求,留出固定的最大值、最小值紅包的金額等;在代碼中調用生成紅包的方法時 splitReward(total,num,max?0.01,min),我傳入的最大值減了 0.01,這樣就保證了里面生成的紅包最大值絕對不會超過我們設置的最大值。

<?phpclass CreateReward{    /*     * 生成紅包     * @param   int          $total               紅包總金額     * @param   int          $num                 紅包總數量     * @param   int          $max                 紅包最大值     *     */    public function random_red($total, $num, $max, $min)    {        // 總共要發的紅包金額,留出一個最大值;        $total = $total - $max;        $reward = new Reward();        $result_merge = $reward->splitReward($total, $num, $max - 0.01, $min);        sort($result_merge);        $result_merge[1] = $result_merge[1] + $result_merge[0];        $result_merge[0] = $max * 100;        foreach ($result_merge as &$v) {            $v = floor($v) / 100;        }        return $result_merge;    }}

實例測試

基礎代碼

先設置好各種初始值。

<?php/** * Created by PhpStorm. * User: lufei * Date: 2017/1/4 * Time: 22:49 */header('content-type:text/html;charset=utf-8');ini_set('memory_limit', '128M');require_once('CreateReward.php');require_once('Reward.php');$total = 50000;$num = 300000;$max = 50;$min = 0.01;$create_reward = new CreateReward();

性能測試

因為 memory_limit 的限制,所以只測了 5 次的均值,結果都在 1.6s 左右。

for ($i=0; $i<5; $i++) {    $time_start = microtime_float();    $reward_arr = $create_reward->random_red($total, $num, $max, $min);    $time_end = microtime_float();    $time[] = $time_end - $time_start;}echo array_sum($time)/5;function microtime_float(){    list($usec, $sec) = explode(" ", microtime());    return ((float)$usec + (float)$sec);}

運行結果:

數據檢查

1) 數值是否有誤

檢測有沒有負值,有沒有最大值,最大值有多少個,有沒有小于最小值的值。

$reward_arr = $create_reward->random_red($total, $num, $max, $min);sort($reward_arr);//正序,最小的在前面$sum = 0;$min_count = 0;$max_count = 0;foreach($reward_arr as $i => $val) {    if ($i<3) {        echo "<br />第".($i+1)."個紅包,金額為:".$val."<br />";    }    if ($val == $max) {          $max_count++;    }    if ($val < $min) {        $min_count++;    }    $val = $val*100;    $sum += $val;}//檢測錢是否全部發完echo '<hr>已生成紅包總金額為:'.($sum/100).';總個數為:'.count($reward_arr).'<hr>';//檢測有沒有小于0的值echo "<br />最大值:".($val/100).',共有'.$max_count.'個最大值,共有'.$min_count.'個值比最小值小';

運行結果:

2) 正態分布情況

注意,出圖的時候,紅包的數量不要給的太大,不然頁面渲染不出來,會崩 。

$reward_arr = $create_reward->random_red($total, $num, $max, $min);$show = array();rsort($reward_arr);// 為了更直觀的顯示正態分布效果,需要將數組重新排序foreach($reward_arr as $k=>$value){    $t=$k%2;    if(!$t) $show[]=$value;;    else array_unshift($show,$value);}echo "設定最大值為:".$max.',最小值為:'.$min.'<hr />';echo "<table style='font-size:12px;width:600px;border:1px solid #ccc;text-align:left;'><tr><td>紅包金額</td><td>圖示</td></tr>";foreach($show as $val){    // 線條長度計算    $width=intval($num*$val*300/$total);    echo "<tr><td> {$val} </td><td width='500px;text-align:left;'><hr style='width:{$width}px;height:3px;border:none;border-top:3px double red;margin:0 auto 0 0px;'></td></tr>";}echo "</table>";

運行結果:

PS:有朋友問我生成的數據有沒有通過數學方法來驗證其是否符合標準正態分布,因為我的數學不好,這個還真沒算過,只是看著覺得像,就當他是了。既然遇到了這個問題,就一定要解決嘛,所以我就用 php 內置函數算了一下,算出來的結果在數據量小的時候還是比較接近正態分布的,但是數據量大起來的時候就不能看了,我整不太明白這個,大家感興趣的可以找一下原因喲。

php 的四個函數:stats_standard_deviation(標準差),stats_variance(方差), stats_kurtosis((峰度),stats_skew(偏度)。使用上面的函數需要安裝 stats 擴展。

以上就是PHP 生成隨機紅包算法的詳細內容,更多請關注電腦知識其它相關文章!

鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
91av在线视频观看| 国产91|九色| 欧美亚洲国产日韩2020| 国产精品福利观看| 国内精品伊人久久| 国产69久久精品成人| 精品无人区太爽高潮在线播放| 色综合天天狠天天透天天伊人| 在线播放精品一区二区三区| 5278欧美一区二区三区| 91久久嫩草影院一区二区| 精品欧美激情精品一区| 97香蕉久久超级碰碰高清版| 亚洲最大成人免费视频| 亚洲国产精久久久久久| 亚洲影院污污.| 欧美国产精品va在线观看| 2019亚洲日韩新视频| 不卡av在线播放| 亚洲日本中文字幕免费在线不卡| 黑人极品videos精品欧美裸| 国产91精品久久久久久久| 高清一区二区三区四区五区| 69影院欧美专区视频| 国产精品看片资源| 日韩精品一二三四区| 欧美老女人在线视频| 欧美日韩午夜剧场| 91在线观看免费观看| 91精品久久久久久久久不口人| 91视频88av| 姬川优奈aav一区二区| 亚洲色图校园春色| 久久激情视频免费观看| 国产精品6699| 日本19禁啪啪免费观看www| 亚洲第一免费播放区| 欧美高清视频在线| 高清一区二区三区四区五区| 日本视频久久久| 日韩一级裸体免费视频| 国产美女精品视频免费观看| 精品日韩中文字幕| 成人观看高清在线观看免费| 亚洲精品女av网站| 精品中文字幕在线| 国产精品视频在线观看| 91精品国产亚洲| 国产精品第七影院| 欧美电影免费播放| 色婷婷综合久久久久| 91免费高清视频| 国产精品96久久久久久又黄又硬| 亚洲午夜av电影| 亚洲综合精品伊人久久| 亚洲精品久久久久中文字幕欢迎你| 亚洲精品国产免费| 日本成人激情视频| 国产精品日韩专区| 成人黄色影片在线| 国产精品亚洲一区二区三区| 精品欧美国产一区二区三区| 国产精品成av人在线视午夜片| 国产亚洲精品日韩| 三级精品视频久久久久| 久久成年人免费电影| 国产精品入口免费视| 日韩视频中文字幕| 国内精久久久久久久久久人| 亚洲色图第三页| 久久国产精品久久精品| 欧美专区国产专区| 揄拍成人国产精品视频| 日韩二区三区在线| 欧美午夜视频在线观看| 91久久精品美女高潮| 国产亚洲精品美女| 夜夜嗨av色综合久久久综合网| 日韩成人激情影院| 亚洲最新视频在线| 亚洲精品免费在线视频| 亚洲专区国产精品| 亚洲综合中文字幕68页| 国产精品爱久久久久久久| 伊人一区二区三区久久精品| 亚洲电影免费观看高清完整版在线观看| 亚洲香蕉av在线一区二区三区| 亚洲欧美在线免费观看| 国内精品久久久久久影视8| 久久久久久av| 精品国内产的精品视频在线观看| 国产91成人video| 欧美黑人国产人伦爽爽爽| 一色桃子一区二区| 91国语精品自产拍在线观看性色| 亚洲r级在线观看| 国产日韩专区在线| 97不卡在线视频| 成人444kkkk在线观看| 国产精品视频免费在线| 一个人看的www久久| 欧美激情videos| 欧美最顶级的aⅴ艳星| 国产91精品青草社区| 欧美国产在线电影| 久久久精品在线观看| 久久久在线视频| 亚洲精品720p| 国模视频一区二区| 国产国语刺激对白av不卡| 亚洲男人第一av网站| 欧美孕妇孕交黑巨大网站| 亚洲人成网站免费播放| 国语自产偷拍精品视频偷| 久久视频在线播放| 操91在线视频| 在线精品高清中文字幕| 亚洲国产精品热久久| 成人性生交xxxxx网站| 久久精视频免费在线久久完整在线看| 在线日韩av观看| 国产精品一区二区三区久久久| 成人免费视频在线观看超级碰| 中文字幕九色91在线| 中文在线资源观看视频网站免费不卡| 成人写真视频福利网| 91精品啪在线观看麻豆免费| 欧美黑人一区二区三区| 国内精品小视频在线观看| 中文字幕成人在线| 亚洲日本欧美日韩高观看| 伊人成人开心激情综合网| 久久免费视频网站| 亚洲美女久久久| 久久精品国产亚洲精品2020| 国产日韩在线亚洲字幕中文| 国产精品高潮呻吟久久av野狼| 欧美日韩国产丝袜另类| 国产伦精品免费视频| 97久久精品人人澡人人爽缅北| 日韩av电影手机在线| 日韩成人免费视频| 尤物九九久久国产精品的分类| 91精品视频免费观看| 最近2019中文字幕第三页视频| 日韩中文字幕视频| 色偷偷88888欧美精品久久久| 久久视频免费在线播放| 青青草精品毛片| 国产精品视频xxx| 欧美日韩国产中文精品字幕自在自线| 欧美美女15p| 欧美精品在线网站| 美女福利精品视频| www.欧美视频| 亚洲欧洲一区二区三区在线观看| 大量国产精品视频| 久久久久久国产精品| 一区二区在线视频| 色噜噜狠狠色综合网图区| 亚洲一区二区三区香蕉| 亚洲成人久久久| 国产精品无码专区在线观看| 成人欧美一区二区三区在线|