这是我的代码,用于计算有理数的不同运算。现在,我的任务是使用assert
实现额外的安全性,以防止溢出。我试图做一些事情,但当我使用-ea
向JVM启用断言时,它开始一直“抛出”断言(即使使用4 > 5
断言条件)。 如何实现此功能以及在 Long
数字上执行此操作的正确方法是什么?
public class Rational {
private final long numerator;
private final long denominator;
private double result;
public Rational(long numerator, long denominator){
this.numerator = numerator;
this.denominator = denominator;
result = (double)numerator/(double)denominator;
}
public Rational plus(Rational b){
assert this.denominator * b.denominator >= Long.MAX_VALUE : "Overflow of denominator in 'PLUS'"; //My attempt
long plusDenominator = this.denominator * b.denominator;
long plusNumerator = ((plusDenominator / this.denominator) * this.numerator) + ((plusDenominator / b.denominator) * b.numerator);
long gcd = gcd(plusNumerator, plusDenominator);
return new Rational(plusNumerator / gcd, plusDenominator / gcd);
}
public Rational minus(Rational b){
long minusDenominator = this.denominator * b.denominator;
long minusNumerator = ((minusDenominator / this.denominator) * this.numerator) - ((minusDenominator / b.denominator) * b.numerator);
long gcd = gcd(minusNumerator, minusDenominator);
return new Rational(minusNumerator / gcd, minusDenominator / gcd);
}
public Rational times(Rational b){
long timesDenominator = this.denominator * b.denominator;
long timesNumerator = this.numerator * b.numerator;
long gcd = gcd(timesDenominator, timesNumerator);
return new Rational(timesNumerator / gcd, timesDenominator / gcd);
}
public Rational divides(Rational b){
long divDenominator = this.denominator * b.numerator;
long divNumerator = this.numerator * b.denominator;
long gcd = gcd(divNumerator, divDenominator);
return new Rational(divNumerator / gcd, divDenominator / gcd);
}
private long gcd(long p, long q){
if(q == 0) return p;
long r = p % q;
return gcd(q, r);
}
public static void main(String[] args){
Rational r1 = new Rational(8, 999999999999999999L);
Rational r2 = new Rational(8 ,999999999999999999L);
System.out.println(r1.plus(r2));
}
}
答案 0 :(得分:2)
测试如下:
assert this.denominator * b.denominator >= Long.MAX_VALUE . . .
不可能是对的。如果this.denominator * b.denominator
溢出,结果可能是负面的;它当然不能大于Long.MAX_VALUE
,并且几乎没有机会等于Long.MAX_VALUE
。您需要一种更有效的方法来检测是否会发生溢出。
通常的做法是向上转换为更大的整数或进行预测试。由于您已经使用long
,因此唯一可用的转发是BigInteger
,我认为您不想使用它。以下是您可以使用预测试的方法:
static final long safeMultiply(long left, long right)
throws ArithmeticException {
if (right > 0
? left > Long.MAX_VALUE/right || left < Long.MIN_VALUE/right
: (right < -1
? left > Long.MIN_VALUE/right || left < Long.MAX_VALUE/right
: right == -1 && left == Long.MIN_VALUE) ) {
throw new ArithmeticException("Long overflow");
}
return left * right;
}
我建议不要使用assert
,因为它可以在运行时关闭。您可以在某处保持一个标志是否发出信号溢出,如果是false
则跳过测试。