• 【踩坑】double和BigDecimal的精度问题


    【踩坑】double和bigdecimal的精度问题

    背景

    今天生产报了个问题,在申报和预算相同的金额的时候,后台返回超出预算。一开始以为是判断逻辑的问题,找了个数据试了下发现重现不出来。又是改数据又是找前端传参最后发现是接受参数处理的问题。

    double转Bigdecimal,调用compare方法没有返回预期结果

    部分代码如下

    balanceFee.compareTo(new BigDecimal(amt)) >= 0
    
    • 1

    debug尝试

    下面两个图是分别对100和100.6
    debug如图
    在这里插入图片描述
    在这里插入图片描述
    debug看上去都好像相同, 但是结果是, 100相同, 100.6不相同

    测试代码

     public static void main(String[] args) {
            double d1 = 6.66;
            double d2 = 666.0 / 100.0;
            double d3 = Double.parseDouble("6.66");
            String s1 = "6.66";
            testDoubleBigdecimal(d1, d2,d3, s1);
        }
    
        private static void testDoubleBigdecimal(double d1, double d2, double d3, String s1) {
            BigDecimal bg1 = new BigDecimal(d1);
            BigDecimal bg2 = new BigDecimal(d2);
            BigDecimal bg3 = new BigDecimal(d3);
            BigDecimal bg4 = new BigDecimal(s1);
            System.out.println("double = " + bg1);
            System.out.println("double / = " + bg2);
            System.out.println("str 2 double = " + bg3);
            System.out.println("str = " + bg4);
            System.out.println("bg1.compareTo(bg2) = " + bg1.compareTo(bg2));
            System.out.println("bg1.compareTo(bg3) = " + bg1.compareTo(bg3));
            System.out.println("bg1.compareTo(bg4) = " + bg1.compareTo(bg4));
            System.out.println("bg2.compareTo(bg3) = " + bg2.compareTo(bg3));
            System.out.println("bg2.compareTo(bg4) = " + bg2.compareTo(bg4));
            System.out.println("bg3.compareTo(bg4) = " + bg3.compareTo(bg4));
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    结果

    分别用666.6和66.66测试

    • 666.6结果:

    double = 666.6000000000000227373675443232059478759765625
    double / = 666.6000000000000227373675443232059478759765625
    str 2 double = 666.6000000000000227373675443232059478759765625
    str = 666.6
    bg1.compareTo(bg2) = 0
    bg1.compareTo(bg3) = 0
    bg1.compareTo(bg4) = 1
    bg2.compareTo(bg3) = 0
    bg2.compareTo(bg4) = 1
    bg3.compareTo(bg4) = 1

    • 66.66结果

    double = 66.659999999999996589394868351519107818603515625
    double / = 66.659999999999996589394868351519107818603515625
    str 2 double = 66.659999999999996589394868351519107818603515625
    str = 66.66
    bg1.compareTo(bg2) = 0
    bg1.compareTo(bg3) = 0
    bg1.compareTo(bg4) = -1
    bg2.compareTo(bg3) = 0
    bg2.compareTo(bg4) = -1
    bg3.compareTo(bg4) = -1

    总结

    其实double有精度问题,这个是大家都知道的. 解决精度问题用BigDecimal也是很常见的手段, 但是这里不知道为什么controller的接口使用了double来接收.

    1. double有精度问题
    2. 使用BigDecimal最好用string来转化

    最坑是在debug的时候, 由于代码是balanceFee.compareTo(new BigDecimal(amt)) >= 0
    第一个balanceFee是字符串转化计算而来的,是准确的, 第二个amt是double, 在debug模式下浮窗显示的值也是精准的, 然而最重要的new BigDecimal(amt)却没有浮窗显示出值.
    这样也就不难理解为什么debug的时候图上看上去是一样的值, 比较的结果却不是0了

  • 相关阅读:
    手写vue3.0 -项目结构初始化
    c++ 类中隐藏的六个(c11之后 八个)默认函数
    kafka 动态扩容现有 topic 的分区数和副本数
    会自动清除的文件——tempfile
    洛谷刷题:循环结构
    python自动化测试工具selenium使用指南
    C++ std::hash 获得字符串哈希值
    arm & docker & sysbench
    本二成为Java 高级开发:回忆大学在南昌实习,那会儿太嫩了~
    Redis面试题(五)
  • 原文地址:https://blog.csdn.net/zzzgd_666/article/details/128138522