什么会使for循环在应该增加时减少?

时间:2019-01-03 01:50:19

标签: java loops for-loop increment decrement

我写了一种方法来计算父亲多久以前是儿子的两倍,以及从现在起多少年才如此。出乎意料的是,它为一个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循环中的计数器在应该增加时如何减少。有人可以解释吗?

(更新:谢谢大家的回答。我不敢相信我忘记了整数溢出。我尝试使变量变长而不是整数,但这使程序变得更慢。无论如何,现在我意识到计数器是一直递增,直到它飞越并降到负值为止。)

3 个答案:

答案 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正在无限制地递增,导致pastFathersAgepastSonsAge变成负数。这导致负整数溢出。发生这种情况是因为您的条件pastFathersAge != 2 * pastSonsAge从未被满足(相反,从未被满足)。直到您的futureFathersAge完全从否定词变回正数,最后定为-2为止。

故事的寓意是确保始终可以满足循环的终止条件。请勿使用!=,而应使用>=<=