我有以下程序平方和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