distanceTo() 整数溢出?
distanceTo() integer overflow?
这是我确定两点之间距离的方法:
// Euclidean distance between this point and that point
public int distanceTo(Point that) {
int distanceX = this.x - that.x;
int distanceY = this.y - that.y;
return (int) Math.sqrt(distanceX * distanceX + distanceY * distanceY);
}
是否可能发生整数溢出,如果是,我该如何预防?
编辑:
为了防止不正确的结果溢出,使用 Math
"exact" 方法:
Math.addExact(int x, int y)
1
Math.subtractExact(int x, int y)
1
Math.multiplyExact(int x, int y)
1
Math.incrementExact(int a)
1
Math.decrementExact(int a)
1
Math.negateExact(int a)
1
Math.toIntExact(long value)
1) 或 long
变体。
如果发生溢出,这些方法将抛出 ArithmeticException
。
public int distanceTo(Point that) throws ArithmeticException {
int distanceX = Math.subtractExact(this.x, that.x);
int distanceY = Math.subtractExact(this.y, that.y);
return (int) Math.sqrt(Math.addExact(Math.multiplyExact(distanceX, distanceX),
Math.multiplyExact(distanceY, distanceY)));
}
当然,使用 long
数学来最小化溢出的可能性可能是谨慎的。
public int distanceTo(Point that) {
long distanceX = Math.subtractExact((long) this.x, (long) that.x);
long distanceY = Math.subtractExact((long) this.y, (long) that.y);
long sumOfSquares = Math.addExact(Math.multiplyExact(distanceX, distanceX),
Math.multiplyExact(distanceY, distanceY));
return Math.toIntExact((long) Math.sqrt(sumOfSquares));
}
当 sumOfSquares
加宽为 double
时,精度可能会略有下降,但在转换为 long
期间丢弃小数点时,精度可能会丢失。
首先你可以使用hypotenuse函数。
那么在远处(-
)可能会发生整数溢出。
解决办法是用double,因为最后的结果是用浮点函数计算的
结果可能和 sqrt(2)*2*Integer.MAX_VALUE
一样大,也溢出了。
所以:
public int distanceTo(Point that) {
double distanceX = ((double)this.x) - that.x;
double distanceY = ((double)this.y) - that.y;
double distance = Math.hypot(distanceX, distanceY);
if (distance + 1 >= Integer.MAX_VALUE) {
throw new ArithmeticException("Integer overflow");
}
return (int) distance; // (int) Math.round?
}
或更整洁(Andreas 也是):
public int distanceTo(Point that) {
double distanceX = ((double)this.x) - that.x;
double distanceY = ((double)this.y) - that.y;
double distance = Math.hypot(distanceX, distanceY);
return Math.toIntExact((long)distance); // (int) Math.round?
}
这是我确定两点之间距离的方法:
// Euclidean distance between this point and that point
public int distanceTo(Point that) {
int distanceX = this.x - that.x;
int distanceY = this.y - that.y;
return (int) Math.sqrt(distanceX * distanceX + distanceY * distanceY);
}
是否可能发生整数溢出,如果是,我该如何预防?
编辑:
为了防止不正确的结果溢出,使用 Math
"exact" 方法:
Math.addExact(int x, int y)
1Math.subtractExact(int x, int y)
1Math.multiplyExact(int x, int y)
1Math.incrementExact(int a)
1Math.decrementExact(int a)
1Math.negateExact(int a)
1Math.toIntExact(long value)
1) 或 long
变体。
如果发生溢出,这些方法将抛出 ArithmeticException
。
public int distanceTo(Point that) throws ArithmeticException {
int distanceX = Math.subtractExact(this.x, that.x);
int distanceY = Math.subtractExact(this.y, that.y);
return (int) Math.sqrt(Math.addExact(Math.multiplyExact(distanceX, distanceX),
Math.multiplyExact(distanceY, distanceY)));
}
当然,使用 long
数学来最小化溢出的可能性可能是谨慎的。
public int distanceTo(Point that) {
long distanceX = Math.subtractExact((long) this.x, (long) that.x);
long distanceY = Math.subtractExact((long) this.y, (long) that.y);
long sumOfSquares = Math.addExact(Math.multiplyExact(distanceX, distanceX),
Math.multiplyExact(distanceY, distanceY));
return Math.toIntExact((long) Math.sqrt(sumOfSquares));
}
当 sumOfSquares
加宽为 double
时,精度可能会略有下降,但在转换为 long
期间丢弃小数点时,精度可能会丢失。
首先你可以使用hypotenuse函数。
那么在远处(-
)可能会发生整数溢出。
解决办法是用double,因为最后的结果是用浮点函数计算的
结果可能和 sqrt(2)*2*Integer.MAX_VALUE
一样大,也溢出了。
所以:
public int distanceTo(Point that) {
double distanceX = ((double)this.x) - that.x;
double distanceY = ((double)this.y) - that.y;
double distance = Math.hypot(distanceX, distanceY);
if (distance + 1 >= Integer.MAX_VALUE) {
throw new ArithmeticException("Integer overflow");
}
return (int) distance; // (int) Math.round?
}
或更整洁(Andreas 也是):
public int distanceTo(Point that) {
double distanceX = ((double)this.x) - that.x;
double distanceY = ((double)this.y) - that.y;
double distance = Math.hypot(distanceX, distanceY);
return Math.toIntExact((long)distance); // (int) Math.round?
}