杰瑞科技汇

Java double转long精度如何处理?

double 的小数部分去掉,只保留整数部分,如何处理小数部分(是四舍五入还是直接截断)以及如何处理超出 long 范围的值,是关键所在。

Java double转long精度如何处理?-图1
(图片来源网络,侵删)

Java 主要提供了以下几种方法来实现 doublelong 的转换,每种方法的行为都不同。


使用强制类型转换 (long)

这是最直接、最常用的方法,它会直接截断小数部分,也就是将 double 向零方向取整。

语法:

long value = (long) doubleValue;

特点:

Java double转long精度如何处理?-图2
(图片来源网络,侵删)
  • 行为: 截断小数部分。
  • 示例:
    • (long) 10.9 结果是 10
    • (long) 10.1 结果是 10
    • (long) -10.9 结果是 -10 (注意,是向零取整,而不是向下取整)
  • 优点: 速度快,语法简单。
  • 缺点: 不进行四舍五入,可能会造成数据精度的损失。

示例代码:

public class DoubleToLongCast {
    public static void main(String[] args) {
        double d1 = 123.456;
        double d2 = 78.999;
        double d3 = -99.8;
        long l1 = (long) d1; // 截断小数部分
        long l2 = (long) d2; // 截断小数部分
        long l3 = (long) d3; // 截断小数部分
        System.out.println("原始值: " + d1 + " -> 转换后: " + l1); // 输出: 原始值: 123.456 -> 转换后: 123
        System.out.println("原始值: " + d2 + " -> 转换后: " + l2); // 输出: 原始值: 78.999 -> 转换后: 78
        System.out.println("原始值: " + d3 + " -> 转换后: " + l3); // 输出: 原始值: -99.8 -> 转换后: -99
    }
}

使用 Math.round() 方法

Math.round() 方法会根据小数部分进行四舍五入,然后返回一个 longint 类型的结果。

语法:

long value = Math.round(doubleValue);

特点:

Java double转long精度如何处理?-图3
(图片来源网络,侵删)
  • 行为: 四舍五入到最接近的整数。
  • 示例:
    • Math.round(10.4) 结果是 10
    • Math.round(10.5) 结果是 11
    • Math.round(-10.5) 结果是 -10 (注意,Java 的 round 方法在 .5 的情况下会向“正无穷”方向取整)
  • 优点: 符合常规的四舍五入规则,适用于需要精确到整数且对精度要求高的场景。
  • 缺点: 比强制类型转换稍慢。

示例代码:

public class DoubleToLongRound {
    public static void main(String[] args) {
        double d1 = 123.456;
        double d2 = 78.5;
        double d3 = -99.5;
        long l1 = Math.round(d1);
        long l2 = Math.round(d2);
        long l3 = Math.round(d3);
        System.out.println("原始值: " + d1 + " -> 转换后: " + l1); // 输出: 原始值: 123.456 -> 转换后: 123
        System.out.println("原始值: " + d2 + " -> 转换后: " + l2); // 输出: 原始值: 78.5 -> 转换后: 79
        System.out.println("原始值: " + d3 + " -> 转换后: " + l3); // 输出: 原始值: -99.5 -> 转换后: -99
    }
}

使用 Math.floor() 方法

Math.floor() 方法会向下取整,即返回小于或等于该 double 值的最大整数。

语法:

long value = (long) Math.floor(doubleValue);

注意:Math.floor() 返回的是 double 类型,所以仍然需要强制转换为 long

特点:

  • 行为: 向下取整。
  • 示例:
    • Math.floor(10.9) 结果是 0,转换为 long 后是 10
    • Math.floor(10.1) 结果是 0,转换为 long 后是 10
    • Math.floor(-10.1) 结果是 -11.0,转换为 long 后是 -11 (注意,这是向下取整)
  • 优点: 在需要向下取整的场景(如计算页数、分组等)非常有用。
  • 缺点: 对于正数,效果和强制类型转换类似;但对于负数,结果完全不同。

示例代码:

public class DoubleToLongFloor {
    public static void main(String[] args) {
        double d1 = 10.9;
        double d2 = -10.1;
        long l1 = (long) Math.floor(d1);
        long l2 = (long) Math.floor(d2);
        System.out.println("原始值: " + d1 + " -> 转换后: " + l1); // 输出: 原始值: 10.9 -> 转换后: 10
        System.out.println("原始值: " + d2 + " -> 转换后: " + l2); // 输出: 原始值: -10.1 -> 转换后: -11
    }
}

使用 Math.ceil() 方法

Math.ceil() (ceiling) 方法会向上取整,即返回大于或等于该 double 值的最小整数。

语法:

long value = (long) Math.ceil(doubleValue);

同样,Math.ceil() 也返回 double 类型,需要强制转换。

特点:

  • 行为: 向上取整。
  • 示例:
    • Math.ceil(10.1) 结果是 0,转换为 long 后是 11
    • Math.ceil(10.9) 结果是 0,转换为 long 后是 11
    • Math.ceil(-10.9) 结果是 -10.0,转换为 long 后是 -10
  • 优点: 在需要向上取整的场景非常有用。
  • 缺点:floor 一样,对于正负数的行为需要注意。

示例代码:

public class DoubleToLongCeil {
    public static void main(String[] args) {
        double d1 = 10.1;
        double d2 = -10.9;
        long l1 = (long) Math.ceil(d1);
        long l2 = (long) Math.ceil(d2);
        System.out.println("原始值: " + d1 + " -> 转换后: " + l1); // 输出: 原始值: 10.1 -> 转换后: 11
        System.out.println("原始值: " + d2 + " -> 转换后: " + l2); // 输出: 原始值: -10.9 -> 转换后: -10
    }
}

处理大数:超出 long 范围的情况

这是一个非常重要的注意事项。double 的表示范围远大于 longdouble 的值超出了 long 的表示范围 (Long.MIN_VALUELong.MAX_VALUE),上述方法会得到意想不到的结果。

long 的范围是: -9,223,372,036,854,775,8089,223,372,036,854,775,807

double 的值超出这个范围时:

  • 对于非常大的正数,强制转换和 Math.floor() 会返回 Long.MAX_VALUE
  • 对于非常小的负数,强制转换和 Math.ceil() 会返回 Long.MIN_VALUE
  • Math.round() 的行为也是类似的,它会返回 Long.MAX_VALUELong.MIN_VALUE

正确的做法是先进行范围检查:

public class DoubleToLongOverflow {
    public static void main(String[] args) {
        double tooBig = 1.0e308; // 一个远大于 Long.MAX_VALUE 的数
        double tooSmall = -1.0e308; // 一个远小于 Long.MIN_VALUE 的数
        // 错误的做法:直接转换,会得到 Long.MAX_VALUE 或 Long.MIN_VALUE
        System.out.println("直接转换超大数: " + (long) tooBig); // 输出: 9223372036854775807 (Long.MAX_VALUE)
        System.out.println("直接转换超小数: " + (long) tooSmall); // 输出: -9223372036854775808 (Long.MIN_VALUE)
        // 正确的做法:先检查范围
        if (tooBig > Long.MAX_VALUE) {
            System.out.println("错误: 值 " + tooBig + " 超出 long 的最大范围。");
        } else if (tooBig < Long.MIN_VALUE) {
            System.out.println("错误: 值 " + tooBig + " 超出 long 的最小范围。");
        } else {
            long result = (long) tooBig;
            System.out.println("安全转换结果: " + result);
        }
    }
}

总结与如何选择

方法 行为 适用场景 注意事项
(long) d 直接截断小数部分 速度要求高,明确知道小数部分可以丢弃的场景(如从时间戳中提取秒数)。 不进行四舍五入,可能损失精度。
Math.round(d) 四舍五入到最接近的整数 需要按照数学规则进行舍入的场景(如财务计算、统计)。 对于 .5 的情况,向正无穷方向取整。
Math.floor(d) 向下取整 需要计算分组、页数等“向下”取整的场景。 返回 double,需强制转换,负数行为与截断不同。
Math.ceil(d) 向上取整 需要计算向上取整的场景(如资源分配)。 返回 double,需强制转换,负数行为与截断不同。
范围检查 - 任何可能超出 long 范围的转换 必须进行,否则会得到错误的最大/最小值。

最佳实践建议:

  1. 首选明确你的需求:你想要截断、四舍五入、向下取整还是向上取整?根据需求选择最合适的 Math 方法或强制类型转换。
  2. 始终考虑边界情况:如果输入的 double 值可能非常大或非常小,务必先进行范围检查,以避免潜在的溢出错误。
  3. 注意精度问题double 本身就存在精度问题,1 + 0.2 并不精确等于 3,在进行转换前,要确保 double 的值已经是你期望的值。
分享:
扫描分享到社交APP
上一篇
下一篇