Java手动溢出处理不良输出

时间:2018-11-14 00:49:07

标签: java

我有以下程序 平方和1 ^ 2 + 2 ^ 2 +…+ N ^ 2计算如下: 输出示例:

  

java SumSquares 2 = 5

     

java SumSquares 3 = 14

     

java SumSquares 1000000 = 333333833333500000

这是我到目前为止所拥有的:

        int N = Integer.parseInt(args[0]);
        int sum = 0;
        long R;

        for (int i = 1; i <= N; i++) {
            R = i * i;
            if (i != R / i) {
                System.err.println("Overflow at i = " + i);
                System.exit(1);
            }
            sum += R;
        }
        System.out.println(sum);
  

我的输出是java SumSquares 100000000                 i = 46341时发生溢出

当46341 ^ 2通过MAX INT时。

我只是无法让程序发布以下说明,以及有关如何获取的任何想法

  

java SumSquares 100000000     i = 3024616时发生溢出

我可以将int更改为long,但是这样就不需要进行溢出检查了。

根据规范:

计算将溢出。我需要通过检查新的和是否(严格地)小于旧的和,来精确确定总和中发生溢出的点。

  

java SumSquares 100000000   i = 3024616时发生溢出

请注意,以上操作必须通过循环中的常规溢出处理来实现,而不是通过某些预定的输入测试来实现。因此,当用于求和的整数类型被更大的类型替换时,您的程序将完全使用新的扩展范围。

只需澄清一下: 是否有可能获得输出

  

java SumSquares 100000000   i = 3024616时发生溢出

按照规范。

2 个答案:

答案 0 :(得分:0)

您有2个错误:

  • R = i * i仍然使用int数学执行乘法运算,并且直到乘法运算溢出到负值之后,才将值扩展为long

    您需要将其中至少一个强制转换为long,例如R = i * (long) i

  • if (i != R / i)不是正确的溢出测试。只需检查long的值是否超出int的范围:if (r > Integer.MAX_VALUE)

static int sumOfSquares(int n) {
    int sum = 0;
    for (int i = 1; i <= n; i++) {
        long r = i * (long) i;
        if (r > Integer.MAX_VALUE) {
            System.err.println("Overflow at i = " + i);
            System.exit(1);
        }
        sum += r;
    }
    return sum;
}

测试

System.out.println(sumOfSquares(2));
System.out.println(sumOfSquares(3));
System.out.println(sumOfSquares(1000000));

输出

5
14
Overflow at i = 46341

防止溢出的另一种方法是使用Math.multiplyExact()Math.addExact()方法。

static int sumOfSquares(int n) {
    int sum = 0;
    for (int i = 1; i <= n; i++) {
        int r = Math.multiplyExact(i, i);
        sum = Math.addExact(sum, r);
    }
    return sum;
}

输出

5
14
Exception in thread "main" java.lang.ArithmeticException: integer overflow
    at java.base/java.lang.Math.addExact(Math.java:825)
    at Test.sumOfSquares(Test.java:12)
    at Test.main(Test.java:6)

或者,如果需要更好的错误消息,请捕获异常:

static int sumOfSquares(int n) {
    int sum = 0;
    for (int i = 1; i <= n; i++) {
        try {
            int r = Math.multiplyExact(i, i);
            sum = Math.addExact(sum, r);
        } catch (@SuppressWarnings("unused") ArithmeticException ignored) {
            System.err.println("Overflow at i = " + i);
            System.exit(1);
        }
    }
    return sum;
}

输出

5
14
Overflow at i = 1861

答案 1 :(得分:0)

无需使用long,您可以在实际执行操作之前检查两个整数的乘法是否会溢出:

int a = 500000; //or -500000
int b = 900000; //or -900000

System.out.println(isOverflowOrUnderflow(a, b));

//Returns true if multiplication of a, b results in an overflow or underflow..
public static boolean isOverflowOrUnderflow(int a, int b) {
    return ((a > Integer.MAX_VALUE / b) || (a < Integer.MIN_VALUE / b) || ((a == -1) && (b == Integer.MIN_VALUE)) || ((b == -1) && (a == Integer.MIN_VALUE)));
}

使用您的代码的示例:

public class Main {
    public static void main (String[] args) {
        int N = Integer.parseInt(args[0]); //Where args[0] = "1000000"..
        int sum = 0;
        long R;

        for (int i = 1; i <= N; i++) {
            if (Main.isOverflowOrUnderflow(i, i)) {
                System.err.println("Overflow at i = " + i);
                System.exit(1);
            }

            R = i * i;
            sum += R;
        }

        System.out.println(sum);
    }

    public static boolean isOverflowOrUnderflow(int a, int b) {
        return ((a > Integer.MAX_VALUE / b) || (a < Integer.MIN_VALUE / b) || ((a == -1) && (b == Integer.MIN_VALUE)) || ((b == -1) && (a == Integer.MIN_VALUE)));
    }
}

输出:

Overflow at i = 46341
Command exited with non-zero status 1