java 四舍五入new BigDecimal(double)及BigDecimal valueOf(double)的区别

最近在研究java的四舍五入,其中有一个方法如下

new BigDecimal(val).setScale(newScale, BigDecimal.ROUND_HALF_DOWN));

其中val是要处理的浮点数

newScale表示要保留小数点后几位

BigDecimal.ROUND_HALF_DOWN表示若舍弃的部分>0.5则进位,否则直接舍弃,说白了就是五舍六入

比如说1.234,保留两位小数处理结果为1.23

比如说1.235,保留两位小数处理结果为1.23

比如说1.236,保留两位小数处理结果为1.24

为了验证我的猜测,马上写几行代码验证下

System.out.println(new BigDecimal(1.234).setScale(2, BigDecimal.ROUND_HALF_DOWN));
System.out.println(new BigDecimal(1.235).setScale(2, BigDecimal.ROUND_HALF_DOWN));
System.out.println(new BigDecimal(1.236).setScale(2, BigDecimal.ROUND_HALF_DOWN));

发现第二条结果与我的猜测不一致,感觉有点受伤

1.23
1.24
1.24

1.235小数点后三位为5,明明是要舍弃的,为何进位了,难道网上的教程都是骗人

折腾了好久,最后发现原来我的写法跟网上别人的还是有细微差别

我的是:new BigDecimal(1.235).setScale(2, BigDecimal.ROUND_HALF_DOWN)

别人家的是:new BigDecimal("1.235").setScale(2, BigDecimal.ROUND_HALF_DOWN),这样的写法结果确实是1.23

可是为何同样的数值,传double类型不行,传String就可以?难道这两种方法初始化的BigDecimal大小不一样?打印出来发现确实不一样

// 打印结果为1.2350000000000000976996261670137755572795867919921875	
System.out.println(new BigDecimal(1.235).toString());
// 打印结果为1.235
System.out.println(new BigDecimal("1.235").toString());

new BigDecimal(1.235)的真实值为1.2350000000000000976996261670137755572795867919921875这一长串数字,舍弃的部分是大于0.5的,所以才进位的。

所以为了避免得到错误的结果还是建议传String类型的值,如果是double类型就用如下方法先转成String再处理

new BigDecimal(String.valueOf(1.235)).setScale(2, BigDecimal.ROUND_HALF_DOWN);
new BigDecimal(Double.toString(1.235)).setScale(2, BigDecimal.ROUND_HALF_DOWN);

还有另一种方法是直接传double类型的

BigDecimal.valueOf(1.235).setScale(2, BigDecimal.ROUND_HALF_DOWN);

查看BigDecimal.valueOf源码,其内部实现其实也是先转成String

/**
 * Translates a {@code double} into a {@code BigDecimal}, using
 * the {@code double}'s canonical string representation provided
 * by the {@link Double#toString(double)} method.
 *
 * <p><b>Note:</b> This is generally the preferred way to convert
 * a {@code double} (or {@code float}) into a
 * {@code BigDecimal}, as the value returned is equal to that
 * resulting from constructing a {@code BigDecimal} from the
 * result of using {@link Double#toString(double)}.
 *
 * @param  val {@code double} to convert to a {@code BigDecimal}.
 * @return a {@code BigDecimal} whose value is equal to or approximately
 *         equal to the value of {@code val}.
 * @throws NumberFormatException if {@code val} is infinite or NaN.
 * @since  1.5
 */
public static BigDecimal valueOf(double val) {
    // Reminder: a zero double returns '0.0', so we cannot fastpath
    // to use the constant ZERO.  This might be important enough to
    // justify a factory approach, a cache, or a few private
    // constants, later.
    return new BigDecimal(Double.toString(val));
}

总结

用BigDecimal处理浮点数时BigDecimal的初始化最好采用如下方法

double d = 1.235;
BigDecimal bd = BigDecimal.valueOf(d);

 

 

posted @ 2019-03-31 22:49  野猿新一  阅读(38)  评论(0编辑  收藏  举报