什么会导致for循环在它应该递增时递减?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了什么会导致for循环在它应该递增时递减?相关的知识,希望对你有一定的参考价值。
我写了一个计算方法来计算父亲多久以前和他儿子一样多的年龄,以及从现在起多少年后这将是真的。出乎意料的是,对于一个8岁的父亲和一个3岁的儿子来说,它回归“2 - 2年前”。同样出人意料的是,对于一个3岁的父亲和一个2岁的儿子,它将在“1年后回归”。我并不担心如何改进代码,因为我已经知道如何做到这一点。相反,我很困惑为什么for循环计数器在它应该增加时似乎递减。
这是我的代码。
public class TwiceAsOld {
public static void twiceAsOld (int currentFathersAge, int currentSonsAge) {
int yearsAgo;
int yearsFromNow;
int pastFathersAge = currentFathersAge;
int pastSonsAge = currentSonsAge;
int futureFathersAge = currentFathersAge;
int futureSonsAge = currentSonsAge;
for (yearsAgo = 0; pastFathersAge != 2 * pastSonsAge; yearsAgo++) {
pastFathersAge--;
pastSonsAge--;
}
System.out.println("The father was last twice as old as the son " + yearsAgo + " years ago.");
for (yearsFromNow = 0; futureFathersAge != 2 * futureSonsAge; yearsFromNow++) {
futureFathersAge++;
futureSonsAge++;
}
System.out.println("The father will be twice as old as the son in " + yearsFromNow + " years from now.");
}
public static void main(String[] args) {
twiceAsOld(8, 3);
twiceAsOld(3, 2);
}
}
使用两次AsOld(8,3)时,for循环的增量似乎已经反转,从0开始倒计数而不是向上计数。有两次AsOld(3,2),-1可能代表一个错误,表明父亲从来没有像他儿子一样大两倍,也永远不会。我不明白的是什么会导致for循环开始递减i值,当它应该增加时。我期待计数器无限增加,直到程序内存不足。
我已经知道如何改进这个程序了,但我很好奇for循环中的计数器如何在它应该增加时减少。任何人都能解释一下吗?
(更新:感谢大家的答案。我不敢相信我忘记了整数溢出。我尝试使变量变长而不是整数,但这使程序更慢。无论如何,现在我意识到计数器一直在增加直到它飞越并以负值降落。)
它变得消极,因为当int计算溢出时,这就是Java中发生的事情。
看看https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.18.2
它说
如果整数加法溢出,则结果是数学和的低阶位,如某些足够大的二进制补码格式所示。如果发生溢出,则结果的符号与两个操作数值的数学和的符号不同。
你没有注意到你的程序运行得很慢吗? :)
对于(8,3)年前的情况,你的for循环保持循环和循环,试图找到父亲两倍的年份,但据我们所知,父亲将来只会变成两倍,但是不是过去。 for循环不知道这个,它会很难找到这样的一年。它努力使yearsAgo
增加超过int
的最大值。这导致overflow,yearsAgo
的值将“回绕”到int
的最小值,这是一个负数。然后这个负数将增加很多次,直到-2。
另一种情况也是如此。
要解决此问题,您可以添加if语句来检查结果是否为负数:
public static void twiceAsOld (int currentFathersAge, int currentSonsAge) {
int yearsAgo;
int yearsFromNow;
int pastFathersAge = currentFathersAge;
int pastSonsAge = currentSonsAge;
int futureFathersAge = currentFathersAge;
int futureSonsAge = currentSonsAge;
for (yearsAgo = 0; pastFathersAge != 2 * pastSonsAge; yearsAgo++) {
pastFathersAge--;
pastSonsAge--;
}
// Here!
if (yearsAgo >= 0) {
System.out.println("The father was last twice as old as the son " + yearsAgo + " years ago.");
}
for (yearsFromNow = 0; futureFathersAge != 2 * futureSonsAge; yearsFromNow++) {
futureFathersAge++;
futureSonsAge++;
}
if (yearsFromNow >= 0) {
System.out.println("The father will be twice as old as the son in " + yearsFromNow + " years from now.");
}
}
您还可以在达到负值时停止循环以使程序更快:
for (yearsAgo = 0; pastFathersAge != 2 * pastSonsAge && yearsAgo >= 0; yearsAgo++) {
当我调试你的代码时,我可以看到yearsAgo
正在无限制地递增,导致pastFathersAge
和pastSonsAge
进入底片。这会导致负整数溢出。发生这种情况是因为你的条件pastFathersAge != 2 * pastSonsAge
永远不会被满足(相反,永远不会满足)。直到你的futureFathersAge
一直走过负面,回到正面,然后最终落在-2。
这个故事的寓意是要确保你的循环终止条件总能得到满足。不要使用!=
,而是使用>=
或<=
。
以上是关于什么会导致for循环在它应该递增时递减?的主要内容,如果未能解决你的问题,请参考以下文章
VBA for Access - Do While 循环停止递减