给出一个硬币游戏:你从一美元开始,硬币翻转。如果它的头部是美元加倍,如果它的尾巴,游戏结束。然而,如果头部被再次翻转,那么现在的收益将翻两番,如果头部被翻转3次8倍,依此类推。悖论是期望值是1/2 * 1 + 1/4 * 2 + 1/8 * 4 ... =无穷大。所以,如果你玩游戏的时间足够长,你应该越来越富有。蒙特卡罗模拟表明没有。这是着名的St. Petersburg Paradox的模拟
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();
}
}
}
}
正如您所看到的那样,我们应该期望数量减少7倍。这让我觉得c#random可能会一遍又一遍地选择相同的数字?它是真的还是我的代码有问题?我该如何解决这个问题?
你有两个错误。你的循环在胜利之后开始,所以获得大胜的机会是1/2 ^ 12,并且你在12岁之后继续增加大奖以获得额外的胜利。
尝试
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
您正在寻找的是游戏达到或继续超过8000美元的概率,即1减去8000美元之前结束概率的总和
结束后的可能性......
总结在$ 8192之前结束的所有概率,你得到0.999755859
所以...你的游戏至少达到8192美元的概率是1-0.999756或0.000244141
将其与1/8192 = 0.0001220703125的概率进行比较,您会发现您的关闭时间约为2倍。
这并没有改变Random
不是随机的良好近似的事实,并且您的预期结果仍将是关闭的。
如果您想使用RNGCryptoServiceProvider,您可以执行以下操作
在你班上的某个地方初始化一个RNGCryptoServiceProvider
RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider();
然后,在分配值a的位置,您可以执行以下操作
//generate a random number between 1 and 2
//allocate an array of bytes to be populated by rngCsp
byte[] randomNumber = new byte[1];
//populate the array with a random byte
rngCsp.GetBytes(randomNumber);
//if the random byte is [0,125] return 1 and if [126,255] return 2
a = randomNumber[0] < 126 ? 1 : 2;
如果您有兴趣计算13个或更多序列发生次数的计数,您可能会对以下代码感兴趣。它可能没有原始代码那么快,但我认为它可能稍微容易阅读和理解(我认为这很重要,但是因为它花了这么长时间来发现原始代码中的错误的部分原因是这跟逻辑有点难。基本上,它保留最后13个项目的队列,并检查它们是否都是1。
请注意,我用于确定预期序列数的计算也与您的不同。我不只是除了8192,而是我做(iterations - (iterations * (1 - (1m/8192m))))
。我不认为计算是100%正确,但它比原始计算更准确。
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();
}
}
}