问题描述
我有一个递归方法,每当随机生成的数字不等于1时,该方法便会自行调用。 我正在尝试测试不同事物的几率,例如minecraft中的神奇宝贝(1/8192)或12眼种子(10 ^ 12),即使我了解堆栈溢出的原因,我也不知道如何解决。使用“线程”会使速度降低很多(不使用线程时每秒可进行5000次计算,使用线程时大约为500次)。
这是代码:
static void shiny()
{
total = 0;
counter += 1;
resetcounter += 1;
if (rdm.Next(8192) + 1 == 1)
{
Console.WriteLine("SHINY !! In: " + counter + " resets.");
}
else
{
if (resetcounter > 7000)
{
Console.WriteLine("Reset. Current: " + counter);
ThreadStart newtask = new ThreadStart(shiny);
Thread task = new Thread(newtask);
task.Start();
}
else
{
Console.WriteLine("Reset. Current: " + counter);
shiny();
}
}
}
我使用resetcounter变量来避免堆栈溢出错误,因为它发生在7k“复位”周围,然后它启动了一个新线程。 我很想了解测试赔率如何可以避免堆栈溢出!
解决方法
了解一些背景信息。 C#和许多其他语言在调用方法时使用call stack,用于局部变量,返回值和其他内容。因此,在调用方法时,堆栈的大小将增加,而在方法返回时,堆栈的大小将减少相同的数量。最大大小通常为1-4Mb,在使用没有明确定义最大深度的递归代码时,很容易达到。
可以将递归函数重写为迭代函数。在某些情况下,需要显式的stack可以大得多,但在这种情况下则不需要。减去线程的示例代码可以按如下方式重写:
void shiny()
{
while (rdm.Next(8192) != 0)
{
counter += 1;
}
Console.WriteLine("SHINY !! In: " + counter + " resets.");
}
尽管这样的实验很有趣,但是您可以显式地计算概率。假设在一轮中发现有光泽的机会是8192中的一,即0.012%,则在n轮后发现至少有光泽的机会为1-(8191/8192)^ n。将其扔进Wolfram alpha中,您会得到probability plot。