杰瑞科技汇

Java double 转 long 会丢失精度吗?

下面我将详细介绍几种转换方法、它们的区别、使用场景以及注意事项。

Java double 转 long 会丢失精度吗?-图1
(图片来源网络,侵删)

核心转换方法

主要有两种官方推荐的转换方法:强制类型转换Math 类的方法


强制类型转换 (long)

这是最直接、最快速的方法,它通过直接截断小数部分来转换。

语法

long value = (long) doubleValue;

工作原理

强制类型转换会直接丢弃 double 的小数部分,只保留整数部分,这相当于向零舍入(Rounding towards zero)。

  • doubleValue 是正数,它会直接去掉小数部分。
  • doubleValue 是负数,它也会直接去掉小数部分(这相当于向零靠拢)。

示例代码

public class DoubleToLongCast {
    public static void main(String[] args) {
        double positiveDouble = 123.45;
        double negativeDouble = -123.45;
        double doubleWithZeroFraction = 100.0;
        // 强制类型转换
        long positiveLong = (long) positiveDouble;
        long negativeLong = (long) negativeDouble;
        long zeroFractionLong = (long) doubleWithZeroFraction;
        System.out.println("原始 double 值: " + positiveDouble + " -> 转换后 long 值: " + positiveLong);
        System.out.println("原始 double 值: " + negativeDouble + " -> 转换后 long 值: " + negativeLong);
        System.out.println("原始 double 值: " + doubleWithZeroFraction + " -> 转换后 long 值: " + zeroFractionLong);
    }
}

输出结果

原始 double 值: 123.45 -> 转换后 long 值: 123
原始 double 值: -123.45 -> 转换后 long 值: -123
原始 double 值: 100.0 -> 转换后 long 值: 100

Math.round()

如果你希望在转换前对小数部分进行四舍五入,而不是直接截断,那么应该使用 Math.round() 方法。

Java double 转 long 会丢失精度吗?-图2
(图片来源网络,侵删)

语法

long value = Math.round(doubleValue);

工作原理

Math.round() 会根据 double 值的小数部分进行四舍五入,然后返回最接近的 long 值。

  • 如果小数部分 >= 0.5,则向正无穷方向舍入(即向上取整)。
  • 如果小数部分 < 0.5,则向负无穷方向舍入(即向下取整)。

示例代码

public class DoubleToLongRound {
    public static void main(String[] args) {
        double double1 = 123.49;
        double double2 = 123.50;
        double double3 = -123.49;
        double double4 = -123.50;
        // 使用 Math.round()
        long long1 = Math.round(double1);
        long long2 = Math.round(double2);
        long long3 = Math.round(double3);
        long long4 = Math.round(double4);
        System.out.println("原始 double 值: " + double1 + " -> 四舍五入后 long 值: " + long1);
        System.out.println("原始 double 值: " + double2 + " -> 四舍五入后 long 值: " + long2);
        System.out.println("原始 double 值: " + double3 + " -> 四舍五入后 long 值: " + long3);
        System.out.println("原始 double 值: " + double4 + " -> 四舍五入后 long 值: " + long4);
    }
}

输出结果

原始 double 值: 123.49 -> 四舍五入后 long 值: 123
原始 double 值: 123.5 -> 四舍五入后 long 值: 124
原始 double 值: -123.49 -> 四舍五入后 long 值: -123
原始 double 值: -123.5 -> 四舍五入后 long 值: -124  // 注意:Java 8+ 中 -0.5 会向远离零的方向舍入

注意:在 Java 8 之前,Math.round(-0.5) 的结果是 0,从 Java 8 开始,Math.round() 的舍入行为遵循了 IEEE 754 标准,即“四舍六入五成双”,但在处理 -0.5 这种情况时,它会向远离零的方向舍入(即 -1)。


Math.floor()Math.ceil()

有时你需要更精确的控制,比如总是向下取整或总是向上取整。

Math.floor() - 向下取整

返回小于或等于参数的最大 double 值,然后需要再强制转换为 long

Java double 转 long 会丢失精度吗?-图3
(图片来源网络,侵删)
double d = 123.99;
long result = (long) Math.floor(d); // 结果是 123

Math.ceil() - 向上取整

返回大于或等于参数的最小 double 值,然后需要再强制转换为 long

double d = 123.01;
long result = (long) Math.ceil(d); // 结果是 124

重要注意事项

精度问题(double 的局限性)

double 是一个 64 位的浮点数,它用二进制科学计数法来表示数字,这意味着很多十进制小数无法被精确表示。

示例:

double value = 123456789012345.67;
long result = (long) value; // 强制转换
System.out.println("原始 double: " + value); // 输出可能是 1.2345678901234567E14
System.out.println("转换后 long: " + result); // 输出可能是 123456789012456

你会发现转换后的 long 值与原始 double 值的整数部分不符,这是因为 value 变量本身在存储时就已经因为精度限制而失真了。

double 值非常大(超出 long 的精确表示范围)或者它本身就是一个不精确的十进制小数,那么转换结果可能不是你期望的,在处理金融或高精度计算时,应避免使用 double,而应使用 BigDecimal

数值溢出

long 的范围是 -2^632^63-1double 值超出了这个范围,转换行为会变得特殊。

  • double 值大于 Long.MAX_VALUE,强制转换会返回 Long.MAX_VALUE
  • double 值小于 Long.MIN_VALUE,强制转换会返回 Long.MIN_VALUE

Math.round() 也会遵循同样的溢出规则。

double tooBig = Double.MAX_VALUE;
double tooSmall = -Double.MAX_VALUE;
System.out.println("(long) " + tooBig + " = " + (long) tooBig); // 输出 9223372036854775807 (Long.MAX_VALUE)
System.out.println("(long) " + tooSmall + " = " + (long) tooSmall); // 输出 -9223372036854775808 (Long.MIN_VALUE)

总结与选择

方法 舍入方式 使用场景
(long) d 直接截断(向零舍入) 当你明确知道只需要丢弃小数部分时,从 999 中获取 123,性能最好。
Math.round(d) 四舍五入 当你需要根据标准四舍五入规则将浮点数转换为最接近的整数时,这是最常见的“四舍五入”需求。
(long) Math.floor(d) 向下取整 当你需要总是取比当前数小的最大整数时,计算页数时 (totalItems / itemsPerPage)
(long) Math.ceil(d) 向上取整 当你需要总是取比当前数大的最小整数时,确保分配足够资源。

  • 想要丢弃小数部分,用 (long)
  • 想要四舍五入,用 Math.round()
  • 需要精确控制舍入方向,用 Math.floor()Math.ceil()
  • 对精度要求极高,请考虑使用 BigDecimal
分享:
扫描分享到社交APP
上一篇
下一篇