• double精度的坑与BigDecimal


    近期经常接触支付相关的功能,在开发及测试过程中,开始金额都使用的是double类型,而近期新进的需求存在支付时打折的情况,也就是会出现如 1.23元的情况,那么这时候问题来了,如果是直接使用1.23进行支付都是不存在问题的。而偏偏在支付前通常需要一些计算。我们的系统支持会员余额与三方支付(微信、支付宝)同时进行,比如一笔待支付的订单是12.8员,其中用户有5块钱的会员余额,剩下的7.8元通过三方支付进行(这里使用微信吧),那么就涉及到double减法,同时微信支付时需要将元转为分,就是7.8x100,这又涉及到了乘法,此时就出现了double精度计算的问题。如下例子:

    double a = 12.3d;
    double b = 5d;
    System.out.println(a-b);  // 7.300000000000001
    
    double c= 1.13d;
    System.out.println(c * 100); // 112.99999999999999

    上面的计算存在了精度问题,这样计算还需要进行四舍五入,比较麻烦。因此我们想到使用BigDecimal来实现小数的计算。最简单的加减乘除运算如下,希望可以帮到遇到同样问题的童鞋:

    package com.blacksonny.utils;
    
    import java.math.BigDecimal;
    
    /**
     * Created by kk on 2015/12/28.<br>
     */
    public class NumericUtils {
    
        /**
         * double 加运算
         * 
         * @param a
         * @param b
         * @return
         */
        public static double add(double a, double b) {
            BigDecimal b1 = new BigDecimal(Double.toString(a));
            BigDecimal b2 = new BigDecimal(Double.toString(b));
            return b1.add(b2).doubleValue();
        }
    
        /**
         * float 加运算
         * 
         * @param a
         * @param b
         * @return
         */
        public static float add(float a, float b) {
            BigDecimal b1 = new BigDecimal(Double.toString(a));
            BigDecimal b2 = new BigDecimal(Double.toString(b));
            return b1.add(b2).floatValue();
        }
    
        /**
         * double 减运算
         * 
         * @param a
         * @param b
         * @return
         */
        public static double subtract(double a, double b) {
            BigDecimal b1 = new BigDecimal(Double.toString(a));
            BigDecimal b2 = new BigDecimal(Double.toString(b));
            return b1.subtract(b2).doubleValue();
        }
    
        /**
         * float 减运算
         * 
         * @param a
         * @param b
         * @return
         */
        public static float subtract(float a, float b) {
            BigDecimal b1 = new BigDecimal(Double.toString(a));
            BigDecimal b2 = new BigDecimal(Double.toString(b));
            return b1.subtract(b2).floatValue();
        }
    
        /**
         * double 乘运算
         *
         * @param a
         * @param b
         * @return
         */
        public static double multiply(double a, double b) {
            BigDecimal b1 = new BigDecimal(Double.toString(a));
            BigDecimal b2 = new BigDecimal(Double.toString(b));
            return b1.multiply(b2).doubleValue();
        }
    
        /**
         * float 乘运算
         *
         * @param a
         * @param b
         * @return
         */
        public static float multiply(float a, float b) {
            BigDecimal b1 = new BigDecimal(Double.toString(a));
            BigDecimal b2 = new BigDecimal(Double.toString(b));
            return b1.multiply(b2).floatValue();
        }
    
        /**
         * double 除运算
         *
         * @param a
         * @param b
         * @return
         */
        public static double divide(double a, double b) {
            BigDecimal b1 = new BigDecimal(Double.toString(a));
            BigDecimal b2 = new BigDecimal(Double.toString(b));
            return b1.divide(b2).doubleValue();
        }
    
        /**
         * float 除运算
         *
         * @param a
         * @param b
         * @return
         */
        public static float divide(float a, float b) {
            BigDecimal b1 = new BigDecimal(Double.toString(a));
            BigDecimal b2 = new BigDecimal(Double.toString(b));
            return b1.divide(b2).floatValue();
        }
    }

    另外在javascript中也存在精度计算的问题,没有什么好的方法,计算时使用parseFloat先转换,再取精度,写法为 parseFloat(xx.xxx).toFixed(2); //2表示取两位小数。

    同时对于常用的需要将一个double转为BigDecimal时,应该使用BigDecimal.valueOf(0.1), 或者new BigDecimal("0.1"), 而不要直接将double类型作为构造方法的入参传入,这种写法有精度的问题。

  • 相关阅读:
    D1
    测试 Collectors 类中相关 API,以及 Collector 接口中 Characteristics 的枚举值
    Servlet 整合 freemarker、如何在 freemarker 中自定义标签
    webLogic javaweb 路径问题 Not allowed to load local resource
    高复用、高兼容的 ajaxForm 上传文件
    Extjs 4+ 中的 combobox 的级联
    Echarts中关于雷达图极坐标值相差过大时的图像展示问题
    java 使用poi操作Excel(2003,2007)实现数据批量导入的一般思路
    java 使用poi操作Excel表格(2003,2007)实现数据的批量导出
    Ext3.4 表格基本操作
  • 原文地址:https://www.cnblogs.com/blacksonny/p/5116267.html
Copyright © 2020-2023  润新知