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

在java中使用long代替int会导致额外的溢出情况。为什么?,java,Java,我为Hackerrank挑战编写了一个解决方案,其中我将大量数字求和到一个总变量中。当我使用ints时,我注意到我在一个测试用例中溢出,但所有其他测试用例都输出了正确的答案。当我将total变量切换为long以避免溢出时,我在两个测试用例中开始溢出(与之前相同,另一个)。一旦我将total、numToSell和lastMax更改为longs,程序就会计算出正确的答案 什么会导致这种情况发生?我希望将变量从int移动到long不会导致溢出 import java.util.*; public c

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

什么会导致这种情况发生?我希望将变量从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);

        }
    }
}
import java.util.*;
公共类解决方案{
公共静态void main(字符串[]args){
扫描仪输入=新扫描仪(系统输入);
int T=in.nextInt();
而(T-->0)
{
int N=in.nextInt();
整数[]价格=新整数[N];
对于(int i=0;i=0;--i)
{
如果(价格[i]是,因为这里

total += numToSell*lastMax;

如果
numToSell
lastMax
int
,那就是整数乘法。int*int=int。然后将
int
添加到
long
中。当
numToSell
时(或
lastMax
)是一个长的乘法指令,特定的乘法指令将如您所期望的那样工作。我注意到您在两个位置执行该数学。

我猜如果您只是将
total
更改为long和left
numToSell
并将
lastMax
更改为int,那么
numToSell*lastMax
仍然会溢出,并给出不正确的结果如果total、numToSell和lastMax都是整数,那么在某些情况下,可能会意外取消并给出正确答案。如果total很长,则不一定会发生这种情况,但其他都是整数

下面是一个循环的示例

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。这是因为total下溢和(2*20000000)将以完全相同的方式溢出。因此这两个值将被抵消

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

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


这种情况下,所有的int都可以工作,所有的long都可以工作,但是混合失败。

你能提供导致问题的最小数量的输入数据吗?我想你可以使用调试器回答你自己的问题,也许还可以对变量的符号进行一些抽查。啊,你是对的。我知道intint可以做32位的乘法,但我认为numToSelllastMax太小,无法溢出int,但它们实际上可能是50k*100k=50亿。在我的特定示例案例中,最后一个合计操作是-1897992076+-426605980=1970369240,这在某种程度上是神奇的正确。法官似乎让这种情况发生在多个隐藏的测试案例上,而不是这个粒子第一个。