java - 如何测试存储在 double 中的值是否适合 long? (四舍五入是,但截断否)

标签 java casting double long-integer truncate

我认为这个问题很直截了当。但这里有一个例子。

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

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

输出:

9

现在数字超出了 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 常量被提升为 double 类型。另一方面,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

double 不足以区分 -9223372036854775808-9223372036854775809.9 ,所以实际上是同一个 double 。在编译过程中它被转换为二进制形式,这两个数字的二进制形式是相同的。因此,编译程序后,您无法区分源代码中是 -9223372036854775808 还是 -9223372036854775809.9

如果您觉得这仍然是问题,请从 BigDecimal 构造 String :

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

关于java - 如何测试存储在 double 中的值是否适合 long? (四舍五入是,但截断否),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32457168/

相关文章:

java - 编码和序列化之间的澄清

将一个 C 结构转换为另一个

将 NSObject 子类转换为非 objc 协议(protocol)时,Swift 崩溃

c - (x < 8) 当 x = -3 时返回 false( double )

optimization - SSE2 使用 GCC 进行双重计算

java - logback 未设置 Spring 日志记录阈值

java - 使用 ChronicleMap.put 时如何避免创建字节数据的新实例

java : Understanding Arrays. asList(T...array) 原始类型方法

c# - 在 C# 中,将接口(interface)列表转换为对象列表的推荐方法是什么?

swift - UIpickerView Swift 3 无法乘以值