关于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

posted @ 2016-06-12 16:05  xunux  阅读(652)  评论(0编辑  收藏  举报