1. 背景の紹介
少し前、会社のビジネスでは、固定の赤い封筒とランダムな赤い封筒に分けられる赤い封筒を生成する必要がありました。最小値と最大値を指定する場合、少なくとも A 最大値である必要があります。最小値は存在できませんが、赤いエンベロープは最小値より小さくすることはできません。
これまでにこれを行ったことがなかったので、少し混乱したため、Baidu に行って調べてみました。見つけたすべての赤いエンベロープ アルゴリズムにはさまざまなバグがあることがわかりました。負の値が計算されたり、最大値を超えたりする可能性がありました。価値があるので、自分でセットすることにしました。
2. 基本的なアイデア
乱数生成に関しては、このブロガーの悲惨な叔父のアイデアを借用しました:
何が起こっているのかまだわかりませんか?関係ないので一緒にコーディングしましょう!原文: たとえば、 1 つの赤い封筒を N 人に渡すことは、実際には N パーセンテージのデータを取得することと同じです。条件は、これらの N パーセンテージの合計 = 100/100 です。これらの N パーセントの平均は 1/N です。 そして、これらの N パーセントのデータは正規分布に準拠します (ほとんどの値は平均値に近づきます)。
解釈: たとえば、1,000 元があり、50 枚の赤い封筒を送る場合、ランダムに 50 個の数字を選択し、$avg/(1/N) を使用してこれら 50 個の数字の平均 $avg を計算します。基本の $mixrand を取得し、ランダムに生成された 50 個の数値を $mixrand で割って、基本の $randVal に対する各数値の割合を取得し、$randVal に 1,000 元を乗じて、各赤い封筒の特定の金額を取得します。 。
<?php /*
* Author:xx_lufei
* Time:2016年9月14日09:55:36
* Note:红包生成随机算法
*/
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 = array();
#定义生成的数据总合sum
$sum = 0;
$t_count = 0;
while ($t_count $randVal) {
#单个红包所占比例randVal
$randVal = round($randVal / $mixrand, 4);
#算出单个红包金额
$single = floor($this->rewardMoney * $randVal);
#小于最小值直接给最小值
if ($single $max) {
$single = $max;
}
#将红包放入结果数组
$rewardArr[] = $single;
}
#对比红包总数的差异、将差值放在第一个红包上
$rewardAll = array_sum($rewardArr);
$rewardArr[0] = $rewardMoney * 100 - ($rewardAll - $rewardArr[0]);#此处应使用真正的总金额rewardMoney,$rewardArr[0]可能小于0
#第一个红包小于0时,做修正
if ($rewardArr[0] 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 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) {
$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 減らされ、生成される赤いエンベロープの最大値が設定した最大値を超えないことが保証されます。
<?php class CreateReward{ /* * 生成红包 * author xx 2016年9月23日13:53:38 * @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; } }4. 散歩に引っ張り出してみる基本コード:各種初期値を設定
<?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.6秒程度。
for($i=0; $irandom_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); }実行結果:
データチェック: 負の値の有無、最大値の有無、最大値の個数、最大値の有無を検出最小値より小さい値
$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第".($i+1)."个红包,金额为:".$val."<br>"; } if ($val == $max) { $max_count++; } if ($val 已生成红包总金额为:'.($sum/100).';总个数为:'.count($reward_arr).'<hr>'; //检测有没有小于0的值 echo "<br>最大值:".($val/100).',共有'.$max_count.'个最大值,共有'.$min_count.'个值比最小值小';実行結果:
正規分布図: 絵を描くとき、あまりにも多くの赤い封筒を与えないでください。ページはレンダリングされず、クラッシュします
$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 "
红包金额 | 图示 |
{$val} |
PS: 友人が、生成されたデータが数学的に以下に準拠しているかどうかを尋ねました。標準正規分布、私の数学は苦手なので、特に考えたこともありませんでした。ただ見た目が似ていたので、彼のものだと思いました。
この問題に遭遇したので、これを解決する必要があるので、PHPの組み込み関数
を使用して計算しました。データ量が少ない場合、計算結果はまだ比較的正規分布に近いですが、データ量が多くなると、データが増えてしまい、今は見ることができません。興味のある方は、その理由を調べてください。 PHPの4つの関数:stats_standard_deviation(標準偏差)、stats_variance(分散)、stats_kurtosis(尖度)、stats_skew(歪度) 上記の関数を使用するには、
インストール
stats拡張子@ダウンロードアドレス5が必要です。この時点で、赤い封筒を書き終えました。50元の昇給が得られるかどうかはわかりませんが、緊急のニーズは解決できるはずです。
そうそう、このコードパッケージのダウンロードも残しました
以上がランダムな赤い封筒を生成するための PHP アルゴリズムの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

aphpDependencyInjectionContaineriSATOULTAINATINAGECLASSDEPTINCIES、強化測定性、テスト可能性、および維持可能性。

SELECT DEPENTENCINGINOFCENT(DI)大規模なアプリケーションの場合、ServicElocatorは小さなプロジェクトまたはプロトタイプに適しています。 1)DIは、コンストラクターインジェクションを通じてコードのテスト可能性とモジュール性を改善します。 2)ServiceLocatorは、センター登録を通じてサービスを取得します。これは便利ですが、コードカップリングの増加につながる可能性があります。

phpapplicationscanbeoptimizedforspeedandEfficiencyby:1)enabingopcacheinphp.ini、2)PreparedStatementswithpordatabasequeriesを使用して、3)LoopswithArray_filterandarray_mapfordataprocessing、4)の構成ngincasaSearverseproxy、5)

PHPemailvalidationinvolvesthreesteps:1)Formatvalidationusingregularexpressionstochecktheemailformat;2)DNSvalidationtoensurethedomainhasavalidMXrecord;3)SMTPvalidation,themostthoroughmethod,whichchecksifthemailboxexistsbyconnectingtotheSMTPserver.Impl

tomakephpapplicationsfaster、followthesesteps:1)useopcodecachinglikeopcacheTostoredscriptbytecode.2)最小化abasequeriesecachingingindexing.3)leveragephp7機能forbettercodeefficiency.4)

依存性注入(DI)は、明示的に推移的な依存関係によりPHPコードのテスト可能性を大幅に改善します。 1)DI分離クラスと特定の実装により、テストとメンテナンスが柔軟になります。 2)3つのタイプのうち、コンストラクターは、状態を一貫性に保つために明示的な式依存性を注入します。 3)DIコンテナを使用して複雑な依存関係を管理し、コードの品質と開発効率を向上させます。

DatabaseQueryoptimizationInpholvesseveralstrategESTOEnhancePerformance.1)selectonlynlynlyndorycolumnStoredatedataTransfer.2)useindexingtospeedupdataretrieval.3)revenmecrycachingtostoreres sultsoffrequent queries.4)


ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

EditPlus 中国語クラック版
サイズが小さく、構文の強調表示、コード プロンプト機能はサポートされていません

PhpStorm Mac バージョン
最新(2018.2.1)のプロフェッショナル向けPHP統合開発ツール

SublimeText3 Linux 新バージョン
SublimeText3 Linux 最新バージョン

WebStorm Mac版
便利なJavaScript開発ツール

ZendStudio 13.5.1 Mac
強力な PHP 統合開発環境
