我写了一种方法来计算父亲多久以前是儿子的两倍,以及从现在起多少年才如此。出乎意料的是,它为一个8岁的父亲和一个3岁的儿子返回了“ -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);
}
}
使用twosAsOld(8,3),for循环的增量似乎已经反转,从0开始向下计数而不是向上计数。在doublesAsOld(3,2)中,-1可能代表错误,表明父亲从未比儿子大两倍,并且永远也不会。我不明白的是什么会导致for循环在应该增加的时候开始减少i值。我期望计数器无限期地增加,直到程序用尽内存。
我已经知道如何改进该程序,但是我很好奇for循环中的计数器在应该增加时如何减少。有人可以解释吗?
(更新:谢谢大家的回答。我不敢相信我忘记了整数溢出。我尝试使变量变长而不是整数,但这使程序变得更慢。无论如何,现在我意识到计数器是一直递增,直到它飞越并降到负值为止。)
答案 0 :(得分:4)
它变为负数是因为当int计算溢出时,这就是Java中发生的情况。
看看 https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.18.2
说
如果整数加法溢出,则结果为数学和的低阶位,以某种足够大的二进制补码格式表示。如果发生溢出,则结果的符号与两个操作数值的数学和的符号不同。
答案 1 :(得分:3)
您是否没有注意到程序运行速度很慢? :)
对于(8,3)年前的案例,您的for循环不断循环,试图找出一年,父亲的年龄是父亲的两倍,但据我们所知,父亲的年龄将仅是父亲的两倍。 >将来,而不是过去。 for循环不知道这一点,它将很难找到这样的一年。尝试 so 努力使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++) {
答案 2 :(得分:1)
调试我的代码时,我可以看到yearsAgo
正在无限制地递增,导致pastFathersAge
和pastSonsAge
变成负数。这导致负整数溢出。发生这种情况是因为您的条件pastFathersAge != 2 * pastSonsAge
从未被满足(相反,从未被满足)。直到您的futureFathersAge
完全从否定词变回正数,最后定为-2为止。
故事的寓意是确保始终可以满足循环的终止条件。请勿使用!=
,而应使用>=
或<=
。