• 关于BigDecimal 和 double 类型保存金钱,以及精度问题,银行家舍入法


    1、 BigDecimal 类型数据 的创建,构造函数 有

     1 public BigDecimal(BigInteger intVal, long val, int scale, int prec);
     2 
     3 public BigDecimal(char[] in, int offset, int len) ;
     4 
     5 public BigDecimal(String val);
     6 
     7 public BigDecimal(double val);
     8 
     9 public BigDecimal(BigInteger val);
    10 
    11 public BigDecimal(int val);
    12 
    13 public BigDecimal(long val);
    View Code

    其中 构造方法 

    public BigDecimal(double val)

    可能是不可预测的,因为double类型数据 有精度问题, 比如 double a = 0.1, new BigDecimal(a); 构造出来的BigDecimal 是不等于 0.1的, 解决方法是 将其转为String 或者用 。

     1         double a = 5.5D;
     2         double b = 4.5D;
     3         double c = 1.465D;
     4         double d = 1.455D;
     5         BigDecimal decimal = new BigDecimal(c).setScale(2, RoundingMode.HALF_EVEN);            //构造的BigDecimal 不等于 1.465, 不精确 :1.4650000000000000799360577730112709105014801025390625
     6         BigDecimal decimal2 = BigDecimal.valueOf(c).setScale(2, RoundingMode.HALF_EVEN);    //这样构造的BigDecimal 才精确
     7         BigDecimal decimal3 = new BigDecimal(c+"").setScale(2, RoundingMode.HALF_EVEN);        //这样构造的BigDecimal 才精确
     8         
     9         
    10         System.out.println(new BigDecimal(a).setScale(0, RoundingMode.HALF_EVEN).doubleValue());
    11         System.out.println(new BigDecimal(b).setScale(0, RoundingMode.HALF_EVEN).doubleValue());
    12         System.out.println(new BigDecimal(c+"").setScale(2, RoundingMode.HALF_EVEN).doubleValue());
    13         System.out.println(new BigDecimal(d).setScale(2, RoundingMode.HALF_EVEN).doubleValue());
    View Code

    2、 BigDecimal 跟String 对象一样是不可变对象, 设置保留小数位数后 返回的是一个新的对象。

    3、BigDecimal 舍入模式模式有 ROUNDING_UP 远离0, ROUNDING_DOWN 接近0, ROUNDING_CEILING 向上进位, ROUNDING_FLOOR 向下靠近, ROUNDING_HALF_UP 四舍五入, ROUNDING_HALF_DOWN 五舍六入, ROUNDING_HALF_EVEN 银行家舍入法,四舍六入,五后非零入,五后为零靠前位奇偶,前偶舍前奇入

        /**
         * Rounding mode to round away from zero.  Always increments the
         * digit prior to a nonzero discarded fraction.  Note that this rounding
         * mode never decreases the magnitude of the calculated value.
         */
        public final static int ROUND_UP =           0;
    
        /**
         * Rounding mode to round towards zero.  Never increments the digit
         * prior to a discarded fraction (i.e., truncates).  Note that this
         * rounding mode never increases the magnitude of the calculated value.
         */
        public final static int ROUND_DOWN =         1;
    
        /**
         * Rounding mode to round towards positive infinity.  If the
         * {@code BigDecimal} is positive, behaves as for
         * {@code ROUND_UP}; if negative, behaves as for
         * {@code ROUND_DOWN}.  Note that this rounding mode never
         * decreases the calculated value.
         */
        public final static int ROUND_CEILING =      2;
    
        /**
         * Rounding mode to round towards negative infinity.  If the
         * {@code BigDecimal} is positive, behave as for
         * {@code ROUND_DOWN}; if negative, behave as for
         * {@code ROUND_UP}.  Note that this rounding mode never
         * increases the calculated value.
         */
        public final static int ROUND_FLOOR =        3;
    
        /**
         * Rounding mode to round towards {@literal "nearest neighbor"}
         * unless both neighbors are equidistant, in which case round up.
         * Behaves as for {@code ROUND_UP} if the discarded fraction is
         * ≥ 0.5; otherwise, behaves as for {@code ROUND_DOWN}.  Note
         * that this is the rounding mode that most of us were taught in
         * grade school.
         */
        public final static int ROUND_HALF_UP =      4;
    
        /**
         * Rounding mode to round towards {@literal "nearest neighbor"}
         * unless both neighbors are equidistant, in which case round
         * down.  Behaves as for {@code ROUND_UP} if the discarded
         * fraction is {@literal >} 0.5; otherwise, behaves as for
         * {@code ROUND_DOWN}.
         */
        public final static int ROUND_HALF_DOWN =    5;
    
        /**
         * Rounding mode to round towards the {@literal "nearest neighbor"}
         * unless both neighbors are equidistant, in which case, round
         * towards the even neighbor.  Behaves as for
         * {@code ROUND_HALF_UP} if the digit to the left of the
         * discarded fraction is odd; behaves as for
         * {@code ROUND_HALF_DOWN} if it's even.  Note that this is the
         * rounding mode that minimizes cumulative error when applied
         * repeatedly over a sequence of calculations.
         */
        public final static int ROUND_HALF_EVEN =    6;
    
        /**
         * Rounding mode to assert that the requested operation has an exact
         * result, hence no rounding is necessary.  If this rounding mode is
         * specified on an operation that yields an inexact result, an
         * {@code ArithmeticException} is thrown.
         */
        public final static int ROUND_UNNECESSARY =  7;
    View Code

    4、 double 类型数据保存到 数据库的 decimal 类型字段时, mybatis是采用了 四舍五入的 舍入模式。

    参考资料:

      1、提高你的Java代码质量吧:不容忽视的四舍五入细节 http://blog.csdn.net/p106786860/article/details/9377471

  • 相关阅读:
    二叉树的节点删除
    PHP开启错误日志详细说明
    jsonpath模块
    Gunicorn-配置详解
    Vmware创建虚拟机步骤说明,详细配置解释
    Python multiprocessing使用详解
    Python定时任务框架apscheduler
    Access-Control-Allow-Origin跨域解决及详细介绍
    web安全:x-content-type-options头设置
    sqlalchemy的基本操作大全
  • 原文地址:https://www.cnblogs.com/xunux/p/5577880.html
Copyright © 2020-2023  润新知