如何测试如果值存储在双适合在长?(四舍五入是,但截断不是)



我觉得这个问题很直接。但这里有一个例子。

下面的例子是OK的。我可以取四舍五入,这里没有截断。

public static void main(String[] args) {
    double d = 9.9;
    long l = (long)d;
    System.out.println(l);
}
输出:

9

现在number超出了long的范围:

public static void main(String[] args) {
    double d = 99999999999999999999999999999999.9;
    long l = (long)d;
    System.out.println(l);
}
输出:

9223372036854775807

这个问题困扰着我。我不能用完全不同的数字继续工作。我宁愿得到一个错误或异常。

在Java中有什么方法可以检测到这个吗?

可以与Long.MIN_VALUELong.MAX_VALUE进行比较:

public static boolean fitsLong(double d) {
    return d >= Long.MIN_VALUE && d < Long.MAX_VALUE;
}
更复杂的方法是使用BigDecimal:
double value = 1234567.9;
long l = BigDecimal.valueOf(value)
                   .setScale(0, RoundingMode.HALF_EVEN)
                   .longValueExact(); // 1234568
double value = 99999999999999999999999999999999.9;
long l = BigDecimal.valueOf(value)
                   .setScale(0, RoundingMode.HALF_EVEN)
                   .longValueExact(); // ArithmeticException

这样可以控制舍入的执行方式。

你可能会问,为什么fitsLong: d < Long.MAX_VALUE有严格的不等式。实际上,这是因为Long.MAX_VALUE本身不能表示为双精度数。当您强制转换(double)Long.MAX_VALUE时,double类型中没有足够的精度来表示它,因此选择最接近的可表示值9223372036854775808.0 (Long_MAX_VALUE+1.0)。因此,如果它是d <= Long.MAX_VALUE,它将返回true作为数字,实际上稍微大一点,因为在这个比较中Long.MAX_VALUE常量被提升为双精度类型。另一方面,Long.MIN_VALUE可以精确地表示为double类型,因此这里我们有>=

同样有趣的是为什么下面的工作:

double value = -9223372036854775809.9; // Long.MIN_VALUE-1.9
System.out.println(fitsLong(value)); // returns true

那是因为你实际上没有从Long.MIN_VALUE中减去任何东西。看到:

double d1 = Long.MIN_VALUE;
double d2 = -9223372036854775809.9;
System.out.println(d1 == d2); // true

双精度不足以区分-9223372036854775808-9223372036854775809.9,因此它们实际上是相同的双精度数。在编译过程中,它被转换成二进制形式,这两个数字的二进制形式是相同的。因此,编译后的程序无法区分-9223372036854775808-9223372036854775809.9是否在源代码中。

如果你觉得这仍然是问题,从String:

构造BigDecimal:
long l = new BigDecimal("-9223372036854775808.2")
                   .setScale(0, RoundingMode.HALF_EVEN)
                   .longValueExact(); // ok, -9223372036854775808
long l = new BigDecimal("-9223372036854775808.9")
                   .setScale(0, RoundingMode.HALF_EVEN)
                   .longValueExact(); // ArithmeticException

当您将浮点类型强制转换为intlong时,结果要么是最接近的整数(向零舍入),要么是intlongMIN_VALUEMAX_VALUE。参考JLS 5.1.3

因此,一种替代方法是进行类型转换,然后测试适当的MIN_VALUEMAX_VALUE

注意Long.MAX_VALUE9223372036854775807…这是您的测试程序输出的数字!

(但是,如果您将浮点类型强制转换为byte, charshort,则此操作不起作用。

相关内容

  • 没有找到相关文章

最新更新