• 使用BigDecimal的坑


    BigDecimal的坑

    BigDecimal常被我们用于计算一些需要精确计算的场景,例如金额的计算。但是,BigDecimal也有很多不为人知的坑。下面,我们就来简单介绍几个常见的坑。

    1、使用valueOf() 替代new BigDecimal

    public static void main(String[] args) {
        BigDecimal bigDecimal1 = new BigDecimal(0.01);
        BigDecimal bigDecimal2 = BigDecimal.valueOf(0.01);
        System.out.println(bigDecimal1);
        System.out.println(bigDecimal2);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    输出结果是:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mwyC8uaE-1656647473350)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1656565943063.png)]

    可以看到,直接new BigDecimal传入0.01的时候,由于0.01这个数字计算机是无法精确表示的,导致传入到BigDecimal中就已经丢失精度。最终输出的结果就有存在误差。而valueOf 则不同,他的底层将Double转化为了String,确保了他的精度不会丢失。

    public static BigDecimal valueOf(double val) {
        return new BigDecimal(Double.toString(val));
    }
    
    • 1
    • 2
    • 3

    总结:尽量使用字符串形式来构造BigDecimal对象,如果实在不行,那么也请使用BigDecimal.valueOf()方法将值进行转换,以此确保我们的精度。

    2、使用compareTo而不是equals进行比较

    public static void main(String[] args) {
        BigDecimal bigDecimal1 = new BigDecimal("1.0");
        BigDecimal bigDecimal2 = new BigDecimal("1.00");
        System.out.println(bigDecimal2.equals(bigDecimal1));
        System.out.println(bigDecimal2.compareTo(bigDecimal1));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    运行结果:
    在这里插入图片描述

    运行结果中,使用equals对比两个BigDecimal的值会等于false,因为BigDecimal的equals会比较两个数字的精度,而compareTo方法只会比较两个数的大小。

    总结:使用compareTo而不是equals比较两个BigDecimal的值。

    3、BigDecimal并不是无限精度

    public static void main(String[] args) {
        BigDecimal bigDecimal1 = new BigDecimal("1.0");
        BigDecimal bigDecimal2 = new BigDecimal("3.0");
        bigDecimal1.divide(bigDecimal2);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    运行结果如下:
    在这里插入图片描述

    这是因为,1 / 3 等于 无限循环小数(0.33333… )。这个时候,我们就必须告诉JVM,我们不需要最精确的结果。修改代码为:

    public static void main(String[] args) {
        BigDecimal bigDecimal1 = new BigDecimal("1.0");
        BigDecimal bigDecimal2 = new BigDecimal("3.0");
        System.out.println(bigDecimal1.divide(bigDecimal2, RoundingMode.HALF_UP));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    运行结果:

    在这里插入图片描述

    4、转化为String要用对方法

    public static void main(String[] args) {
        BigDecimal bigDecimal = BigDecimal.valueOf(12345678902132123113213.12345678912345678);
        //必要时,使用科学计数法
        System.out.println(bigDecimal.toString());
        //不使用科学计数法
        System.out.println(bigDecimal.toPlainString());
        //工程计算中经常使用的记录数字的方法,类似科学计数法,但要求是10的幂必须是3的倍数
        System.out.println(bigDecimal.toEngineeringString());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    运行结果:
    在这里插入图片描述

    总结:

    1. toString():如果必要的时候,使用科学计数法。
    2. toPlainString():不使用科学计数法
    3. toEngineeringString():工程计算中经常使用的记录数字的方法,类似科学计数法,但要求是10的幂必须是3的倍数
  • 相关阅读:
    【Kubernetes | Pod 系列】Pod 的基本管理(3)——对 Pod 的删除与修改
    HBase入门至进阶以及开发等知识梳理
    Flutter环境配置遇到的问题
    VLAN(Virtual LAN)虚拟局域网
    组合数学笔记-特殊计数数列
    Java项目基于SpringBoot藏区特产销售系统,可作为毕业设计
    HarmonyOS应用开发-AnimationDemo体验分享
    Web前端开发的过程:深入剖析与精彩演绎
    FG6223EUUD系列模块选型参考
    无刷直流电机(BLDC)
  • 原文地址:https://blog.csdn.net/weixin_44741023/article/details/125555990