Java手动溢出处理不需要的输出



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

java SumSquares 2=5

java SumSquares 3=14

java SumSquares 1000000=333333 833333500000

以下是迄今为止我所拥有的:

        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 100000000i=46341 时溢出

当46341^2通过MAX INT.时

我只是无法让程序发出以下说明,任何关于如何获得的想法

java SumSquares 100000000i=3024616 时溢出

我可以将int更改为long,但这将消除溢出检查的需要。

来自规范:

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

java SumSquares 100000000i=3024616 时溢出

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

只是澄清一下:有可能得到输出吗

java SumSquares 100000000i=3024616 时溢出

根据规范。

您有两个错误:

  • 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

不必使用longs,您可以在实际执行操作之前检查两个整数的乘积是否会溢出:

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

最新更新