01-浮点数精度问题bug

浮点数精度问题: 用实际生产环境一个发现的BUG 为例,进行记录;

01-问题背景

合作方对价格字段 要求 .00 标准格式 ; 也就是2位小数点;
因此我方对接开发代码对价格字段专门写一个方法,目的就是输出 保留两位小数的字符串
方法明细:

package org.example;


import java.math.BigDecimal;
import java.text.DecimalFormat;

/**
 * Author: kaka@bug.com
 * Date:   2023/12/8-18:40
 * ---------------------------------------
 * Desc:   输出保留两位小数的字符串
 */
public class Test {
   

    public static void main(String[] args) throws Exception {
   
        double p1 = 235.6;
        String pr1 = getBookPriceToString(p1);

        double p2 = 157.7;
        String pr2 = getBookPriceToString(p2);
        System.out.println(pr1); // 输出235.60
        System.out.println(pr2); // 输出157.7
    }

    // 总的来说,这段代码的目的是为了保证价格的字符串形式总是有两位小数,如果原始价格的小数部分不足两位,则会进行补"0"的操作。
    public static String getBookPriceToString(Double buyPrice) throws Exception {
   
        Double buPrice1 = buyPrice * 100;
        Integer roundNumber = buPrice1.intValue();
        String buyPriceStr = buyPrice.toString();
        if (roundNumber % 10 > 0) {
   
            return buyPriceStr;
        }
        if (roundNumber % 100 > 0) {
   
            return buyPriceStr + "0";
        }
        return buyPrice.intValue() + ".00";
    }


    /*
    * 这段代码的主要功能是将传入的buyPrice(购买价格)转换为字符串格式,并根据其小数部分的情况进行不同的处理。

Double buPrice1 = buyPrice * 100;:将buyPrice乘以100,目的是为了后续判断价格的小数部分是否存在。

Integer roundNumber = buPrice1.intValue();:将乘以100后的价格转换为整数,这样就可以通过取余的方式来判断小数部分的情况。

String buyPriceStr = buyPrice.toString();:将buyPrice转换为字符串,为后续的返回做准备。

if (roundNumber % 10 > 0) { return buyPriceStr; }:如果价格的小数部分的十分位大于0(即价格的小数部分不是0.X0的形式),则直接返回原始价格的字符串形式。

if (roundNumber % 100 > 0) { return buyPriceStr + "0"; }:如果价格的小数部分的百分位大于0(即价格的小数部分是0.0X的形式),则在原始价格的字符串形式后面加上"0"。

return buyPrice.intValue() + ".00";:如果价格的小数部分为0(即价格为整数),则在价格后面加上".00"。

总的来说,这段代码的目的是为了保证价格的字符串形式总是有两位小数,如果原始价格的小数部分不足两位,则会进行补"0"的操作。
    * */

}

当输入157.7时候, debug运行计算时候的过程如下图:
61635f0b8985a5368478b195a13b36d.jpg

02-改善方法

package org.example;


import java.math.BigDecimal;
import java.text.DecimalFormat;

/**
 * Author: method1
 * Date:   2023/12/8-18:40
 * ---------------------------------------
 * Desc:   描述该类的作用
 */
public class Test {
   

    public static void main(String[] args) throws Exception {
   
        double p1 = 235.6;
        String pr1 = getBookPriceToString(p1);

        double p2 = 157.7;
        String pr2 = getBookPriceToString(p2);
        System.out.println(pr1); // 输出235.60
        System.out.println(pr2); // 输出157.7

        System.out.println(getBookPriceToStringNew(235.6)); // 输出235.60
        System.out.println(getBookPriceToStringNew(157.7)); // 输出157.70
    }

    // 总的来说,这段代码的目的是为了保证价格的字符串形式总是有两位小数,如果原始价格的小数部分不足两位,则会进行补"0"的操作。
    public static String getBookPriceToString(Double buyPrice) throws Exception {
   
        Double buPrice1 = buyPrice * 100;
        Integer roundNumber = buPrice1.intValue();
        String buyPriceStr = buyPrice.toString();
        if (roundNumber % 10 > 0) {
   
            return buyPriceStr;
        }
        if (roundNumber % 100 > 0) {
   
            return buyPriceStr + "0";
        }
        return buyPrice.intValue() + ".00";
    }

    // 优化后 方法的目的应该是:输出保留两位小数的字符串
    public static String getBookPriceToStringNew(Double buyPrice) throws Exception {
   
        DecimalFormat df = new DecimalFormat("0.00");
        return df.format(buyPrice);
    }
}
package org.example;


import java.math.BigDecimal;
import java.text.DecimalFormat;

/**
 * Author: method2
 * Date:   2023/12/8-18:40
 * ---------------------------------------
 * Desc:   
 */
public class Test {
   

    public static void main(String[] args) throws Exception {
   
        double p1 = 235.6;
        String pr1 = getBookPriceToString(p1);

        double p2 = 157.7;
        String pr2 = getBookPriceToString(p2);
        System.out.println(pr1); // 输出235.60
        System.out.println(pr2); // 输出157.7

        System.out.println(getBookPriceToStringNew(235.6)); // 输出235.60
        System.out.println(getBookPriceToStringNew(157.7)); // 输出157.70

        System.out.println(getBookPriceToString2(157.7)); // 输出157.70
        System.out.println(getBookPriceToString3(157.7)); // 157.7

    }

    // 目的是为了保证价格的字符串形式总有两位小数,如果原始价格的小数部分不足两位,则会进行补"0"的操作。
    public static String getBookPriceToString(Double buyPrice) throws Exception {
   
        Double buPrice1 = buyPrice * 100;
        Integer roundNumber = buPrice1.intValue();
        String buyPriceStr = buyPrice.toString();
        if (roundNumber % 10 > 0) {
   
            return buyPriceStr;
        }
        if (roundNumber % 100 > 0) {
   
            return buyPriceStr + "0";
        }
        return buyPrice.intValue() + ".00";
    }

    public static  String getBookPriceToString2(Double buyPrice) throws Exception {
   
        if (buyPrice == null) {
   
            throw new Exception("buyPrice cannot be null");
        }
        if (buyPrice <= 0) {
   
            throw new Exception("buyPrice must be greater than 0");
        }
        DecimalFormat df = new DecimalFormat("#.00");
        return df.format(buyPrice);
    }

    // 优化后 方法的目的应该是:输出保留两位小数的字符串
    public static String getBookPriceToStringNew(Double buyPrice) throws Exception {
   
        DecimalFormat df = new DecimalFormat("0.00");
        return df.format(buyPrice);
    }

    // 实际上线代码
    public static String getBookPriceToString3(Double buyPrice) throws Exception {
   
        BigDecimal price = BigDecimal.valueOf(buyPrice);
        DecimalFormat df = new DecimalFormat("#.00");
        return df.format(price);
    }
}

综上所述

浮点数精度问题 可以通过 BigDecimal 或者 DecimalFormat 来解决;

相关推荐

  1. 点数精度问题

    2024-01-23 07:30:05       37 阅读
  2. 纯C++设置点数精度

    2024-01-23 07:30:05       15 阅读
  3. MySQL变量的点数问题处理

    2024-01-23 07:30:05       11 阅读
  4. 系统语言德语时点数转化问题

    2024-01-23 07:30:05       34 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-01-23 07:30:05       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-23 07:30:05       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-23 07:30:05       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-23 07:30:05       18 阅读

热门阅读

  1. Selenium 自动化截取网页指定区域截图

    2024-01-23 07:30:05       28 阅读
  2. Flink对接Kafka的topic数据消费offset设置参数

    2024-01-23 07:30:05       34 阅读
  3. Eureka基础知识总结(微服务)

    2024-01-23 07:30:05       33 阅读
  4. jupyter notebook删除kernel & conda 删除虚拟环境

    2024-01-23 07:30:05       30 阅读
  5. Chrome扩展之通信

    2024-01-23 07:30:05       32 阅读
  6. C语言常见面试题:什么是宏,宏的作用是什么?

    2024-01-23 07:30:05       18 阅读
  7. Linux Bash编程man帮助手册

    2024-01-23 07:30:05       30 阅读
  8. 【数据结构】树套树

    2024-01-23 07:30:05       39 阅读
  9. 【webrtc】AudioSendStream的创建

    2024-01-23 07:30:05       30 阅读