我有以下程序 平方和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时发生溢出
按照规范。
答案 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