[英]How to break out of this loop
我正在研究Euler項目編號5.我沒有使用Google搜索,因為這通常會導致SO得到答案。 所以,這就是我所擁有的:
private int Euler5(int dividend, int divisor)
{
if (divisor < 21)
{
// if it equals zero, move to the next divisor
if (dividend % divisor == 0)
{
divisor++;
return Euler5(dividend, divisor);
}
else
{
dividend++;
return Euler5(dividend, 1); // move to the dividend
}
}
// oh hey, the divisor is above 20, so what's the dividend
return dividend;
}
在我看來,這是有道理的。 然而VS2012給了我一個StackOverFlowException,表明我確保我沒有進入無限循環或使用遞歸。 我的問題是,為什么這是一個無限循環? 我有一種感覺,我錯過了一些完全愚蠢的東西。
編輯
由於人們似乎一直在發帖,我會重申我沒有使用谷歌因為害怕絆倒答案。 我不想要問題的答案。 我只想知道為什么我得到了例外。
給傑森的答案+1,這清楚地解釋了問題。
現在有一些解決方案! 我知道至少有三種方法可以從算法中刪除遞歸:
如果所有遞歸調用都是尾調用 ,則算法是尾遞歸的 ,這意味着它們是在返回之前完成的最后一件事。 如果您不清楚,請使用Google查找更好的示例。
通過調整參數和使用goto而不是真實的調用,可以很容易地轉換這些算法。 再看一下你的例子:
private int Euler5(int dividend, int divisor)
{
tail_call:
if (divisor < 21)
{
// if it equals zero, move to the next divisor
if (dividend % divisor == 0)
{
divisor++;
goto tail_call; // return Eular5(dividend, divisor);
}
else
{
dividend++;
// return Eular5(dividend, 1); // move to the dividend
divisor = 1;
goto tail_call;
}
}
// oh hey, the divisor is above 20, so what's the dividend
return dividend;
}
噢!嗨! 它的功能完全相同,但具有固定的堆棧大小(沒有調用,只有跳轉)。 現在有人會說:“呃......搞砸了!他們是邪惡的!死了,死了!”。 我想這是少數合法用途之一。 畢竟,如果你的編譯器足夠聰明,它本身就會進行尾調用優化(F#實際上是這樣,C#沒有,JIT可能在x64上執行,而不是在x86上執行)。
但對於那些人我會說:看起來好一點。 因為每個if / else分支的末尾都有一個goto,所以我可以將它完全移出“if”。 現在我有類似“start:if(X){Y(); goto start;}”想想看,它只是一個“while(X)Y()”循環。 所以你剛剛找到函數的迭代版本:
private int Euler5(int dividend, int divisor)
{
while (divisor < 21)
{
// if it equals zero, move to the next divisor
if (dividend % divisor == 0)
{
divisor++;
}
else
{
dividend++;
divisor = 1;
}
}
// oh hey, the divisor is above 20, so what's the dividend
return dividend;
}
太好了!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.