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" 方法:

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?
}