// 抽奖盈亏计算测试示例 // 基于实际业务逻辑的模拟数据 // 模拟一个抽奖活动的配置 const mockActivity = { id: 1, name: "春节抽奖活动", price_draw: 1000, // 门票价格:10元 = 1000分 status: 1 }; // 模拟奖项配置 const mockRewards = [ { id: 1, name: "iPhone 15 Pro", weight: 1, quantity: 10, product_id: 101, cost: 800000 // 成本:8000元 = 800000分 }, { id: 2, name: "AirPods Pro", weight: 10, quantity: 50, product_id: 102, cost: 200000 // 成本:2000元 = 200000分 }, { id: 3, name: "小米手环", weight: 100, quantity: 200, product_id: 103, cost: 20000 // 成本:200元 = 20000分 }, { id: 4, name: "优惠券10元", weight: 1000, quantity: -1, // -1 表示不限量 product_id: null, cost: 1000 // 成本:10元 = 1000分(平台补贴) }, { id: 5, name: "谢谢参与", weight: 5000, quantity: -1, product_id: null, cost: 0 // 无成本 } ]; // 计算理论概率和期望支出 function calculateTheoreticalData(rewards) { // 筛选有效奖项(weight > 0 且 quantity != 0) const validRewards = rewards.filter(r => r.weight > 0 && r.quantity !== 0); // 计算总权重 const totalWeight = validRewards.reduce((sum, r) => sum + r.weight, 0); // 计算每个奖项的理论概率和期望支出 const results = validRewards.map(reward => { const probability = reward.weight / totalWeight; const expectedCost = probability * reward.cost; // 单次抽奖的期望支出 return { ...reward, probability, expectedCost }; }); // 总期望支出(单次抽奖) const totalExpectedCost = results.reduce((sum, r) => sum + r.expectedCost, 0); return { rewards: results, totalWeight, totalExpectedCost }; } // 模拟抽奖结果 function simulateDraws(rewards, sampleSize) { const theoretical = calculateTheoreticalData(rewards); const results = {}; // 初始化结果统计 theoretical.rewards.forEach(reward => { results[reward.id] = { ...reward, count: 0, simulatedCost: 0 }; }); // 模拟抽奖 for (let i = 0; i < sampleSize; i++) { const random = Math.random(); let cumulativeProbability = 0; // 根据概率选择奖项 for (const reward of theoretical.rewards) { cumulativeProbability += reward.probability; if (random <= cumulativeProbability) { results[reward.id].count++; results[reward.id].simulatedCost += reward.cost; break; } } } return { theoretical, simulated: Object.values(results), sampleSize }; } // 计算盈亏指标 function calculateProfitMetrics(activity, simulation) { const { theoretical, simulated, sampleSize } = simulation; const ticketPrice = activity.price_draw; // 理论计算 const theoreticalRevenue = ticketPrice * sampleSize; const theoreticalPayout = theoretical.totalExpectedCost * sampleSize; const theoreticalProfit = theoreticalRevenue - theoreticalPayout; const theoreticalMargin = theoreticalProfit / theoreticalRevenue; // 模拟计算 const simulatedRevenue = ticketPrice * sampleSize; const simulatedPayout = simulated.reduce((sum, r) => sum + r.simulatedCost, 0); const simulatedProfit = simulatedRevenue - simulatedPayout; const simulatedMargin = simulatedProfit / simulatedRevenue; return { theoretical: { revenue: theoreticalRevenue, payout: theoreticalPayout, profit: theoreticalProfit, margin: theoreticalMargin }, simulated: { revenue: simulatedRevenue, payout: simulatedPayout, profit: simulatedProfit, margin: simulatedMargin } }; } // 运行测试 function runLotteryProfitTest() { console.log("=== 抽奖盈亏分析测试 ==="); console.log(`活动: ${mockActivity.name}`); console.log(`门票价格: ¥${(mockActivity.price_draw / 100).toFixed(2)}`); console.log(""); // 理论计算 const theoreticalData = calculateTheoreticalData(mockRewards); console.log("--- 理论概率分析 ---"); console.log(`总权重: ${theoreticalData.totalWeight}`); console.log(`单次期望支出: ¥${(theoreticalData.totalExpectedCost / 100).toFixed(4)}`); console.log(`单次期望利润: ¥${((mockActivity.price_draw - theoreticalData.totalExpectedCost) / 100).toFixed(4)}`); console.log(""); theoreticalData.rewards.forEach(reward => { console.log(`${reward.name}:`); console.log(` 权重: ${reward.weight}, 概率: ${(reward.probability * 100).toFixed(4)}%`); console.log(` 成本: ¥${(reward.cost / 100).toFixed(2)}, 期望支出: ¥${(reward.expectedCost / 100).toFixed(4)}`); }); console.log("\n--- 模拟结果 (样本数: 10000) ---"); const simulation = simulateDraws(mockRewards, 10000); const metrics = calculateProfitMetrics(mockActivity, simulation); console.log("理论值:"); console.log(` 总收入: ¥${(metrics.theoretical.revenue / 100).toFixed(2)}`); console.log(` 总支出: ¥${(metrics.theoretical.payout / 100).toFixed(2)}`); console.log(` 总利润: ¥${(metrics.theoretical.profit / 100).toFixed(2)}`); console.log(` 利润率: ${(metrics.theoretical.margin * 100).toFixed(2)}%`); console.log("\n模拟值:"); console.log(` 总收入: ¥${(metrics.simulated.revenue / 100).toFixed(2)}`); console.log(` 总支出: ¥${(metrics.simulated.payout / 100).toFixed(2)}`); console.log(` 总利润: ¥${(metrics.simulated.profit / 100).toFixed(2)}`); console.log(` 利润率: ${(metrics.simulated.margin * 100).toFixed(2)}%`); console.log("\n--- 各奖项模拟结果 ---"); simulation.simulated.forEach(result => { const simulatedRate = result.count / simulation.sampleSize; const theoreticalRate = result.probability; const diff = Math.abs(simulatedRate - theoreticalRate) * 100; console.log(`${result.name}:`); console.log(` 模拟次数: ${result.count}, 模拟概率: ${(simulatedRate * 100).toFixed(3)}%`); console.log(` 理论概率: ${(theoreticalRate * 100).toFixed(3)}%, 差异: ${diff.toFixed(3)}%`); console.log(` 模拟支出: ¥${(result.simulatedCost / 100).toFixed(2)}`); }); // 验证大数定律 console.log("\n--- 大数定律验证 ---"); const largeSample = simulateDraws(mockRewards, 100000); largeSample.simulated.forEach(result => { const simulatedRate = result.count / largeSample.sampleSize; const theoreticalRate = result.probability; const diff = Math.abs(simulatedRate - theoreticalRate) * 100; console.log(`${result.name}: 模拟概率 ${(simulatedRate * 100).toFixed(4)}% vs 理论概率 ${(theoreticalRate * 100).toFixed(4)}%, 差异 ${diff.toFixed(4)}%`); }); } // 运行测试 runLotteryProfitTest();