可控概率抽奖算法

说明

本文PHP语言去实现,只实现核心可控概率引擎,库存判断等其它业务需要其它代码配合实现。

代码

php 复制代码
/**
 * @function 封装可控概率的抽奖功能
 * @param    $arr        array  数据集合
 * @param    $weight_key string 权重字段
 * @return   array       被选中的元素
 */
function controllableProbability($arr, $weight_key = 'weight') {
    $total_probability = 0;
    foreach($arr as $v) {
        $total_probability = bcadd($total_probability, $v[$weight_key], 2);
    }
    $rand = mt_rand(1, intval($total_probability));
    foreach ($arr as $val) {
        if ($rand <= $val[$weight_key]) {break;}
        $rand -= $val[$weight_key];
        next($arr);
    }
    //想要返回key,使用return key($arr);
    return current($arr);
}

调用

  1. weight权重概率字段,不是概率字段,不需要总和为100
  2. 如下,代表16个人抽奖,有10人是谢谢惠顾,有5人中2元,有1人中5元,有0人中50W。
php 复制代码
$arr = [
    ['id' => 1, 'name' => '谢谢惠顾', 'weight' => 10],
    ['id' => 2, 'name' => '中2元', 'weight' => 5],
    ['id' => 3, 'name' => '中5元', 'weight' => 1],
    ['id' => 4, 'name' => '中50W', 'weight' => 0],
];
//参数1是数组,参数2是告诉controllableProbability函数哪个字段为改概率字段
controllableProbability($arr, 'weight');

验算

php 复制代码
$a = 0; $b = 0; $c = 0; $d = 0;
for($i = 0; $i < 1600000; $i++) {
    $res = controllableProbability($arr, 'weight');
    if($res['id'] == 1) $a ++;
    if($res['id'] == 2) $b ++;
    if($res['id'] == 3) $c ++;
    if($res['id'] == 4) $d ++;
}
echo "$a $b $c $d";

3轮抽奖,每轮抽160万次,可得以下表格:

轮次 谢谢惠顾实际次数 谢谢惠顾期望值 中2元实际次数 中2元期望值 中5元实际次数 中5元期望值 中50W实际次数 中50W期望次
1 999323 1000000 500374 500000 100303 100000 0 0
2 1001144 1000000 498732 500000 100124 100000 0 0
3 999285 1000000 500662 500000 100053 100000 0 0

以谢谢惠顾为例纵向对比:

项目 第一轮 第2轮 第3轮
谢谢惠顾实际次数 999323 1001144 999285
谢谢惠顾期望次数 100000 100000 100000
谢谢惠顾实际概率 62.46% 62.57% 62.46%
谢谢惠顾期望概率 62.50% 62.50% 62.50%
误差率 -0.04% +0.07% -0.04%

技术上:随机范围可控,但是随机值不可控,随机值可控就不叫随机了,有误差正常,本来随机就是个概率问题。

业务上:可通过库存的限制和其它业务逻辑来避免误差带来的问题。

数值上:若硬要实现0误差的精确控制,则需要动态获取权重值,抽中哪条数据,递减那条数据的权重值即可(同时要避免mt_rand();函数参数2小于参数1的情况出现)。

相关推荐
sjsjs115 分钟前
【数据结构-扫描线】力扣57. 插入区间
数据结构·算法·leetcode
王哈哈嘻嘻噜噜7 分钟前
数据结构中线性表的定义和特点
数据结构·算法
代码对我眨眼睛14 分钟前
springboot从分层到解耦
spring boot·后端
The Straggling Crow22 分钟前
go 战略
开发语言·后端·golang
一杯茶一道题27 分钟前
LeetCode 260. 只出现一次的数字 III
算法·leetcode
MogulNemenis28 分钟前
力扣415周赛
java·数据结构·算法·leetcode
ai安歌29 分钟前
【JavaWeb】利用IDEA2024+tomcat10配置web6.0版本搭建JavaWeb开发项目
java·开发语言·后端·tomcat·web·intellij idea
Rense132 分钟前
常用的基于无线射频( UWB)室内定位技术的原理与算法
算法
zzhnwpu32 分钟前
代码随想录算法训练营第三七天| 动态规划:完全背包理论基础 518.零钱兑换II 377. 组合总和 Ⅳ 322. 零钱兑换
算法·leetcode·动态规划
为暗香来39 分钟前
MySQL学习(视图总结)
数据库·学习·mysql