使用long代替int会导致java中出现额外溢出的情况。为什么?

时间:2014-09-19 02:30:36

标签: java

我为Hackerrank挑战编写了一个解决方案,其中我将大量数字汇总到一个总变量中。当我使用整数时,我注意到我在一个测试用例中溢出,但所有其他测试用例都输出了正确的答案。当我将total变量切换为长以避免溢出时,我开始溢出两个测试用例(与之前相同,另一个)。将totalnumToSell lastMax更改为long后,程序会计算出正确的答案。

会导致这种情况发生的原因是什么?我希望将变量从int移到long应该永远不会导致溢出。

import java.util.*;

public class Solution {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int T = in.nextInt();
        while(T-->0)
        {
            int N = in.nextInt(); 
            int[] price = new int[N];

            for(int i = 0; i < N; ++i)
            {
                price[i] = in.nextInt();
            }

            int lastMax = price[N-1]; //works when this and numToSell are longs
            int numToSell = 0; 
            long total = 0; //if this is also an int, only overflows in one case in my samples
            for(int i  = N - 2; i >= 0; --i)
            {
                if(price[i] <= lastMax)
                {
                    ++numToSell;
                    total -= price[i];
                }
                else
                {
                    total += numToSell*lastMax;
                    lastMax = price[i];
                    numToSell = 0;
                }
            }
            total += numToSell*lastMax;
            System.out.println(total);

        }
    }
}

在受影响的测试用例中,N为39,384,数组中的每个数字介于1到100000之间。

3 个答案:

答案 0 :(得分:2)

是的,因为这里

total += numToSell*lastMax;

如果numToSelllastMax int是整数乘法。 int * int = int。然后,您将int添加到long。当numToSell(或lastMax)很长时,特定的乘法指令将按预期工作。我注意到你在两个地方进行数学运算。

答案 1 :(得分:0)

我猜你是否刚刚将total更改为long并将numToSelllastMax更改为int,那么numToSell*lastMax仍然会溢出并给出错误的结果已添加到total

答案 2 :(得分:0)

如果total,numToSell和lastMax都是整数,那么在某些情况下,事情可以取消,并且会意外地给出正确的答案。如果总数很长但另一个是整数,则不一定会发生这种情况。

这是一个遍历循环的例子。

prices = {2000001,2000000,2000000,2000000};
lastMax = 2000000;
numToSell = 0;
total = 0;
loop:
  iteration 1:
    numToSell = 1;
    total = -2000000  
  iteration 2:
    numToSell = 2;
    total = -4000000  // oh no, we underflowed if we are int, but not long!
  iteration 3:
    total = -4000000 + (2 * 2000000)  // let's take a deeper look at this below
    numToSell = 0;
    lastMax = 20000001
total += 0; 

让我们来看看这一行:总计= -4000000 +(2 * 2000000)

如果total,numToSell和lastMax都是整数,那么total = 0.这是因为总下溢和(2 * 20000000)将以完全相同的方式溢出。所以两人取消了。

如果它们都是长的,那么没有任何溢出,所以总数= -40000000 +(2 * 2000000)= 0.

如果总数很长,那么当设置为-4000000时总数不会下溢。但是,(2 * 2000000)是一个整数,它将溢出并成为负数。所以总数不会为零!

这是一个所有整数都有效的情况,所有长篇都有效,但混合失败。