C# 计算随机分布中序列出现的频率时出现意外结果
给你一个硬币游戏:你从一美元开始,一枚硬币被翻转。如果是正面,美元就会翻倍,如果是反面,游戏就结束了。然而,如果头部再次翻转,收益现在是原来的四倍,如果头部翻转3倍于8倍,依此类推。矛盾的是期望值是1/2*1+1/4*2+1/8*4…=无穷 因此,如果你玩游戏的时间足够长,你应该会越来越富有。蒙特卡罗模拟表明并非如此。 这是模拟著名的C# 计算随机分布中序列出现的频率时出现意外结果,c#,random,C#,Random,给你一个硬币游戏:你从一美元开始,一枚硬币被翻转。如果是正面,美元就会翻倍,如果是反面,游戏就结束了。然而,如果头部再次翻转,收益现在是原来的四倍,如果头部翻转3倍于8倍,依此类推。矛盾的是期望值是1/2*1+1/4*2+1/8*4…=无穷 因此,如果你玩游戏的时间足够长,你应该会越来越富有。蒙特卡罗模拟表明并非如此。 这是模拟著名的 使用系统; 使用System.Collections.Generic; 使用System.Linq; 使用系统文本; 使用System.Threading.Tas
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Threading.Tasks;
名称空间悲伤
{
班级计划
{
静态void Main(字符串[]参数)
{
Random rnd=新的Random(Environment.TickCount);
双倍总和=0;
int-bigWins=0;
两次迭代=1000;
对于(intz=0;z<10;z++)
{
迭代次数*=10;
for(双i=1;i 如果(sum>8000&&sum你要寻找的是游戏达到或持续超过8000美元的概率,即1减去8000美元之前结束的概率之和
在…之后结束的概率
- 0轮1/2$2
- 1轮1/4$4
- 两轮1/8$8
- 3轮1/16$16(与1/(2^(轮+1))相同)
- 12轮1/2^13$8192(在您的代码中,您只差一轮,12次获胜后您将获得$8192,而不是13次
在8192美元之前结束的所有概率之和为0.999755859
所以…你的游戏价格至少达到8192美元的概率是1-0.999756或0.000244141
将其与1/8192=0.000122703125的概率进行比较,您会发现您的偏差约为2倍
这并没有改变这样一个事实,即Random
不是Random的一个很好的近似值,并且您的预期结果仍然是不正确的
如果要使用,可以执行以下操作
在类中的某个位置初始化RNGCryptoServiceProvider
RNGCryptoServiceProvider rngCsp=new RNGCryptoServiceProvider();
然后,在分配值a的地方,可以执行以下操作
//生成一个介于1和2之间的随机数
//分配要由rngCsp填充的字节数组
字节[]随机数=新字节[1];
//用随机字节填充数组
rngCsp.GetBytes(随机数);
//如果随机字节为[0125],则返回1;如果为[126255],则返回2
a=随机数[0]<126?1:2;
您要寻找的是游戏达到或持续超过8000美元的概率,即1减去8000美元之前结束的概率之和
在…之后结束的概率
- 0轮1/2$2
- 1轮1/4$4
- 两轮1/8$8
- 3轮1/16$16(与1/(2^(轮+1))相同)
- 12轮1/2^13$8192(在您的代码中,您只差一轮,12次获胜后您将获得$8192,而不是13次
在8192美元之前结束的所有概率之和为0.999755859
所以…你的游戏价格至少达到8192美元的概率是1-0.999756或0.000244141
将其与1/8192=0.000122703125的概率进行比较,您会发现您的偏差约为2倍
这并没有改变这样一个事实,即Random
不是Random的一个很好的近似值,并且您的预期结果仍然是不正确的
如果要使用,可以执行以下操作
在类中的某个位置初始化RNGCryptoServiceProvider
RNGCryptoServiceProvider rngCsp=new RNGCryptoServiceProvider();
然后,在分配值a的地方,可以执行以下操作
//生成一个介于1和2之间的随机数
//分配要由rngCsp填充的字节数组
字节[]随机数=新字节[1];
//用随机字节填充数组
rngCsp.GetBytes(随机数);
//如果随机字节为[0125],则返回1;如果为[126255],则返回2
a=随机数[0]<126?1:2;
您有两个错误。您的循环在获胜后开始,因此大胜的几率为1/2^12,并且您在12之后继续增加大胜,以获得更多的胜利
试一试
你有两个错误。你的循环在赢了之后开始,所以大赢的几率是1/2^12,并且你在12之后继续增加大赢,以获得更多的赢
试一试
如果您对计算13个或13个以上的序列出现的次数感兴趣,您可能会对下面的代码感兴趣。它可能没有原始代码快,但我认为它可能更容易阅读和理解(我认为这一点很重要,但之所以花了这么长时间才发现原始代码中的错误,部分原因是有点难以遵循逻辑)。基本上,它保留了最后13项的队列,并检查它们是否都是1
请注意,我用于确定预期序列数的计算也与您的不同。我不只是除以8192,而是除以(迭代次数-(迭代次数*(1-(1m/8192m)))
。我不认为该计算是100%正确的,但它比原始计算更准确
使用系统;
使用System.Collections.Generic;
使用System.Linq;
名称空间控制台EAPP4
{
内部课程计划
{
私有静态void Main(字符串[]args)
{
var queue=新队列();
var rnd=新的随机数(Environment.TickCount);
int-bigWins=0;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Sorrow
{
class Program
{
static void Main(string[] args)
{
Random rnd = new Random(Environment.TickCount);
double totalSum = 0;
int bigWins = 0;
double iterations = 1000;
for (int z = 0; z < 10; z++)
{
iterations *= 10;
for (double i = 1; i < iterations; i++)
{
int sum = 1;
int a = 1;
while (a == 1)
{
//generate a random number between 1 and 2
a = rnd.Next(1, 3);
if (a == 1)
{
sum *= 2;
}
if (sum > 8000&&sum<12000)// given discrete probability landing 13 times
{
// if the sum is over 8000 that means that it scored 1 13 times in a row (2^13) - that should happen
//once every 8192 times. Given that we run the simulation 100 000 000 times it should hover around
// 100 000 000/8192
//However is much , much bigger
bigWins++;
}
}
totalSum += sum;
}
Console.WriteLine("Average gain over : "+iterations+" iterations is:" + totalSum / iterations);
Console.WriteLine("Expected big wins: " + iterations / 8192 + " Actual big wins: " + bigWins);
Console.WriteLine();
}
}
}
}
static void Main(string[] args)
{
Random rnd = new Random(Environment.TickCount);
double iterations = 1000;
for (int z = 0; z < 10; z++)
{
double totalSum = 0;
int bigWins = 0;
iterations *= 10;
for (double i = 1; i < iterations; i++)
{
int sum = 2;
int a = 1;
while (a == 1)
{
//generate a random number between 1 and 2
a = rnd.Next(1, 3);
if (a == 1)
{
sum *= 2;
}
if (sum > 8000)
{
// if the sum is over 8000 that means that it scored 1 12 times in a row (2^12) - that should happen
//once every 4096 times. Given that we run the simulation 100 000 000 times it should hover around
// 100 000 000/4096
bigWins++;
break;
}
}
totalSum += sum;
}
Console.WriteLine("Average gain over : " + iterations + " iterations is:" + totalSum / iterations);
Console.WriteLine("Expected big wins: " + iterations / 4096 + " Actual big wins: " + bigWins);
Console.WriteLine();
}
Console.ReadKey();
}
Average gain over : 10000 iterations is:12.6774
Expected big wins: 2.44140625 Actual big wins: 1
Average gain over : 100000 iterations is:14.09468
Expected big wins: 24.4140625 Actual big wins: 21
Average gain over : 1000000 iterations is:14.022718
Expected big wins: 244.140625 Actual big wins: 249
Average gain over : 10000000 iterations is:14.0285748
Expected big wins: 2441.40625 Actual big wins: 2456
Average gain over : 100000000 iterations is:14.00012582
Expected big wins: 24414.0625 Actual big wins: 24574
Average gain over : 1000000000 iterations is:14.000105548
Expected big wins: 244140.625 Actual big wins: 244441
Average gain over : 10000000000 iterations is:13.9990068676
Expected big wins: 2441406.25 Actual big wins: 2440546
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp4
{
internal class Program
{
private static void Main(string[] args)
{
var queue = new Queue<int>();
var rnd = new Random(Environment.TickCount);
int bigWins = 0;
long iterations = 10000000;
const int sequenceLength = 13;
double probability = 1 / Math.Pow(2, sequenceLength);
for (int z = 0; z < iterations; z++)
{
var a = rnd.Next(1, 3);
queue.Enqueue(a);
if (queue.Count == sequenceLength)
{
if (queue.Distinct().Count() == 1 && queue.First() == 1)
{
bigWins++;
}
queue.Dequeue();
}
}
Console.WriteLine("Expected big wins: " + (iterations - (iterations * (1 - probability))) + " Actual big wins: " + bigWins);
Console.ReadLine();
}
}
}