C# 计算随机分布中序列出现的频率时出现意外结果

C# 计算随机分布中序列出现的频率时出现意外结果,c#,random,C#,Random,给你一个硬币游戏:你从一美元开始,一枚硬币被翻转。如果是正面,美元就会翻倍,如果是反面,游戏就结束了。然而,如果头部再次翻转,收益现在是原来的四倍,如果头部翻转3倍于8倍,依此类推。矛盾的是期望值是1/2*1+1/4*2+1/8*4…=无穷 因此,如果你玩游戏的时间足够长,你应该会越来越富有。蒙特卡罗模拟表明并非如此。 这是模拟著名的 使用系统; 使用System.Collections.Generic; 使用System.Linq; 使用系统文本; 使用System.Threading.Tas

给你一个硬币游戏:你从一美元开始,一枚硬币被翻转。如果是正面,美元就会翻倍,如果是反面,游戏就结束了。然而,如果头部再次翻转,收益现在是原来的四倍,如果头部翻转3倍于8倍,依此类推。矛盾的是期望值是1/2*1+1/4*2+1/8*4…=无穷 因此,如果你玩游戏的时间足够长,你应该会越来越富有。蒙特卡罗模拟表明并非如此。 这是模拟著名的

使用系统;
使用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();
        }
    }
}