Maison développement back-end tutoriel php Algorithme PHP pour générer des enveloppes rouges aléatoires

Algorithme PHP pour générer des enveloppes rouges aléatoires

Dec 21, 2019 pm 01:43 PM
php

Algorithme PHP pour générer des enveloppes rouges aléatoires

Idée de base

En termes de génération de nombres aléatoires, j'ai appris de ce blogueur @Le misérable oncle Idée :

Texte original : Par exemple, si vous souhaitez distribuer 1 enveloppe rouge à N personnes, cela équivaut en fait à obtenir N données en pourcentage. La condition est que la somme de ces N pourcentages = 100/. 100. La moyenne de ces N pourcentages est de 1/N. Et ces N pourcentages de données sont conformes à une distribution normale (la plupart des valeurs sont relativement proches de la moyenne).

Interprétation : Par exemple, si j'ai 1 000 yuans et que j'envoie 50 enveloppes rouges, je choisirai au hasard 50 nombres, puis calculerai la moyenne moyenne de ces 50 nombres, en utilisant avg/(1/N) , et vous obtiendrez un mixrand de nombre de base, puis diviserez les 50 nombres générés aléatoirement par le mixrand pour obtenir le pourcentage de randVal de chaque nombre par rapport à la base, puis multiplierez randVal par 1 000 yuans pour obtenir le montant spécifique de chaque enveloppe rouge. .

Implémentation de l'algorithme

Parler ne coûte pas cher, montre-moi ton code !

Algorithme de génération de base :

<?php
/*
 * 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 = [];
        // 定义生成的数据总合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);
        }
    }
}
Copier après la connexion

Considérez les détails

Le code ci-dessous est utilisé pour contrôler une logique métier spécifique et mettre de côté des montants fixes maximum et minimum d'enveloppe rouge en fonction de besoins spécifiques lors de l'appel de splitReward(total ; ,num,max−0.01,min) dans le code pour générer des enveloppes rouges, la valeur maximale que j'ai transmise a été réduite de 0,01. Cela garantit que la valeur maximale de l'enveloppe rouge générée ne dépassera jamais la valeur maximale que nous avons définie.

<?php
class 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;
    }
}
Copier après la connexion

Test d'instance

Code de base

Définissez d'abord diverses valeurs initiales.

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

Test de performance

En raison de la limitation de memory_limit, je n'ai mesuré la moyenne que 5 fois, et les résultats étaient tous autour de 1,6 s.

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);
}
Copier après la connexion

Résultats d'exécution :

Vérification des données

1) Si la valeur est fausse

Détecté oui Il n'y a pas de valeurs négatives, y a-t-il une valeur maximale, combien de valeurs maximales y a-t-il et y a-t-il une valeur inférieure à la valeur minimale.

$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 &#39;<hr>已生成红包总金额为:&#39;.($sum/100).&#39;;总个数为:&#39;.count($reward_arr).&#39;<hr>&#39;;
//检测有没有小于0的值
echo "<br />最大值:".($val/100).&#39;,共有&#39;.$max_count.&#39;个最大值,共有&#39;.$min_count.&#39;个值比最小值小&#39;;
Copier après la connexion

Résultats d'exploitation :

2) Distribution normale

Notez que lors du dessin, ne donnez pas trop d'enveloppes rouges sinon, le. la page ne peut pas être rendue et plantera.

$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.&#39;,最小值为:&#39;.$min.&#39;<hr />&#39;;
echo "<table style=&#39;font-size:12px;width:600px;border:1px solid #ccc;text-align:left;&#39;><tr><td>红包金额</td><td>图示</td></tr>";
foreach($show as $val)
{
    // 线条长度计算
    $width=intval($num*$val*300/$total);
    echo "<tr><td> {$val} </td><td width=&#39;500px;text-align:left;&#39;><hr style=&#39;width:{$width}px;height:3px;border:none;border-top:3px double red;margin:0 auto 0 0px;&#39;></td></tr>";
}
echo "</table>";
Copier après la connexion

Résultats d'exécution :

PS : Un ami m'a demandé si les données générées avaient été vérifiées mathématiquement pour se conformer à la distribution normale standard, car je ne suis pas bon en mathématiques. Je n'y ai pas vraiment pensé, je lui ressemblais et je pensais que c'était lui. Maintenant que j'ai rencontré ce problème, je dois le résoudre, j'ai donc utilisé la fonction intégrée de PHP pour le calculer. Le résultat calculé est encore relativement proche d'une distribution normale lorsque la quantité de données est petite, mais lorsque la quantité de données est faible. augmente, ça ne peut pas. Regardez, je ne comprends pas très bien cela. Si cela vous intéresse, vous pouvez en découvrir la raison.

Quatre fonctions de php : stats_standard_deviation (écart type), stats_variance (variance), stats_kurtosis (kurtosis), stats_skew (asymétrie). L'utilisation des fonctions ci-dessus nécessite l'installation de l'extension stats

.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

AI Hentai Generator

AI Hentai Generator

Générez AI Hentai gratuitement.

Article chaud

R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Meilleurs paramètres graphiques
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Comment réparer l'audio si vous n'entendez personne
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: Comment déverrouiller tout dans Myrise
4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Guide d'installation et de mise à niveau de PHP 8.4 pour Ubuntu et Debian Guide d'installation et de mise à niveau de PHP 8.4 pour Ubuntu et Debian Dec 24, 2024 pm 04:42 PM

PHP 8.4 apporte plusieurs nouvelles fonctionnalités, améliorations de sécurité et de performances avec une bonne quantité de dépréciations et de suppressions de fonctionnalités. Ce guide explique comment installer PHP 8.4 ou mettre à niveau vers PHP 8.4 sur Ubuntu, Debian ou leurs dérivés. Bien qu'il soit possible de compiler PHP à partir des sources, son installation à partir d'un référentiel APT comme expliqué ci-dessous est souvent plus rapide et plus sécurisée car ces référentiels fourniront les dernières corrections de bogues et mises à jour de sécurité à l'avenir.

Discuter de CakePHP Discuter de CakePHP Sep 10, 2024 pm 05:28 PM

CakePHP est un framework open source pour PHP. Il vise à faciliter grandement le développement, le déploiement et la maintenance d'applications. CakePHP est basé sur une architecture de type MVC à la fois puissante et facile à appréhender. Modèles, vues et contrôleurs gu

Téléchargement de fichiers CakePHP Téléchargement de fichiers CakePHP Sep 10, 2024 pm 05:27 PM

Pour travailler sur le téléchargement de fichiers, nous allons utiliser l'assistant de formulaire. Voici un exemple de téléchargement de fichiers.

Comment configurer Visual Studio Code (VS Code) pour le développement PHP Comment configurer Visual Studio Code (VS Code) pour le développement PHP Dec 20, 2024 am 11:31 AM

Visual Studio Code, également connu sous le nom de VS Code, est un éditeur de code source gratuit – ou environnement de développement intégré (IDE) – disponible pour tous les principaux systèmes d'exploitation. Avec une large collection d'extensions pour de nombreux langages de programmation, VS Code peut être c

Guide rapide CakePHP Guide rapide CakePHP Sep 10, 2024 pm 05:27 PM

CakePHP est un framework MVC open source. Cela facilite grandement le développement, le déploiement et la maintenance des applications. CakePHP dispose d'un certain nombre de bibliothèques pour réduire la surcharge des tâches les plus courantes.

Comment analysez-vous et traitez-vous HTML / XML dans PHP? Comment analysez-vous et traitez-vous HTML / XML dans PHP? Feb 07, 2025 am 11:57 AM

Ce tutoriel montre comment traiter efficacement les documents XML à l'aide de PHP. XML (Language de balisage extensible) est un langage de balisage basé sur le texte polyvalent conçu à la fois pour la lisibilité humaine et l'analyse de la machine. Il est couramment utilisé pour le stockage de données et

Expliquez les jetons Web JSON (JWT) et leur cas d'utilisation dans les API PHP. Expliquez les jetons Web JSON (JWT) et leur cas d'utilisation dans les API PHP. Apr 05, 2025 am 12:04 AM

JWT est une norme ouverte basée sur JSON, utilisée pour transmettre en toute sécurité des informations entre les parties, principalement pour l'authentification de l'identité et l'échange d'informations. 1. JWT se compose de trois parties: en-tête, charge utile et signature. 2. Le principe de travail de JWT comprend trois étapes: la génération de JWT, la vérification de la charge utile JWT et l'analyse. 3. Lorsque vous utilisez JWT pour l'authentification en PHP, JWT peut être généré et vérifié, et les informations sur le rôle et l'autorisation des utilisateurs peuvent être incluses dans l'utilisation avancée. 4. Les erreurs courantes incluent une défaillance de vérification de signature, l'expiration des jetons et la charge utile surdimensionnée. Les compétences de débogage incluent l'utilisation des outils de débogage et de l'exploitation forestière. 5. L'optimisation des performances et les meilleures pratiques incluent l'utilisation des algorithmes de signature appropriés, la définition des périodes de validité raisonnablement,

Programme PHP pour compter les voyelles dans une chaîne Programme PHP pour compter les voyelles dans une chaîne Feb 07, 2025 pm 12:12 PM

Une chaîne est une séquence de caractères, y compris des lettres, des nombres et des symboles. Ce tutoriel apprendra à calculer le nombre de voyelles dans une chaîne donnée en PHP en utilisant différentes méthodes. Les voyelles en anglais sont a, e, i, o, u, et elles peuvent être en majuscules ou en minuscules. Qu'est-ce qu'une voyelle? Les voyelles sont des caractères alphabétiques qui représentent une prononciation spécifique. Il y a cinq voyelles en anglais, y compris les majuscules et les minuscules: a, e, i, o, u Exemple 1 Entrée: String = "TutorialSpoint" Sortie: 6 expliquer Les voyelles dans la chaîne "TutorialSpoint" sont u, o, i, a, o, i. Il y a 6 yuans au total

See all articles