概述
BigDecimal
首先 说一下自己遇到的问题
System.out.println(new BigDecimal("111.1212335")
.setScale(6, BigDecimal.ROUND_HALF_UP));//111.121234
System.out.println(new BigDecimal("111.1212335")
.setScale(6, BigDecimal.ROUND_HALF_DOWN));//111.121233
System.out.println(new BigDecimal("111.12345678")
.setScale(4, BigDecimal.ROUND_HALF_UP));//111.1235
System.out.println(new BigDecimal("111.12345678")
.setScale(4, BigDecimal.ROUND_HALF_DOWN));//111.1235
// 问题为啥这里的 ROUND_HALF_DOWN 小数点后第五位是5 为啥会给第四位进一??
ROUND_HALF_UP 与 ROUND_HALF_DOWN 的区别
先看看文档怎么解释的
ROUND_HALF_UP
若舍弃部分 (>=.5),则作 ROUND_UP ;否则,作 ROUND_DOWN 。
ROUND_HALF_DOWN
若舍弃部分 ( > 5) ROUND_UP;否则,作 ROUND_DOWN 。
ROUND_UP
总是在非 0 舍弃小数(即截断)之前增加数字。
ROUND_DOWN
从不在舍弃(即截断)的小数之前增加数字。
ROUND_UP 与 ROUND_DOWN 实例
// ROUND_DOWN 舍入模式向零舍入 不管是0还是9都不加 相当于 截取
double a4 = new BigDecimal("111.1934567").setScale(1,BigDecimal.ROUND_DOWN).doubleValue(); //111.1
System.out.println(a4);
// ROUND_UP 舍入模式从零开始 非 0舍弃小数加1
double a5 = new BigDecimal("111.1034567").setScale(1,BigDecimal.ROUND_UP).doubleValue();//111.2
double a6 = new BigDecimal("111.1934567").setScale(1,BigDecimal.ROUND_UP).doubleValue();//111.2
System.out.println(a5);
System.out.println(a6);
System.out.println(new BigDecimal("111.10").setScale(1, BigDecimal.ROUND_UP));//111.1
System.out.println(new BigDecimal("111.101").setScale(1, BigDecimal.ROUND_UP));//111.2
好了 看到这 我们再来看看 这个问题到底是为什么??
// "111.121233 5" 这个例子保留六位小数,第六位之后开始 是.5 = .50 所以 up 进位, down 不进位
// 而111.12345678 这个例子保留四位小数 此数第四位后是.5678 > .50 所以两个都要进位
// 下面这个.51 > .50也一样 都会进位
System.out.println(new BigDecimal("111.123451").setScale(4, BigDecimal.ROUND_HALF_UP));//111.1235
System.out.println(new BigDecimal("111.123451").setScale(4, BigDecimal.ROUND_HALF_DOWN));//111.1235
截取出保留小数位数之后的数字(也就是舍弃部分)与 5 做比较 如果 (>=.5),则作 ROUND_UP
下面我们整体了解一下BIgDecimal
引言
float和double类型的主要设计目标是为了科学计算和工程计算。他们执行二进制浮点运算,这是为了在广域数值范围上提供较为精确的快速近似计算而精心设计的。然而,它们没有提供完全精确的结果,所以不应该被用于要求精确结果的场合。但是,商业计算往往要求结果精确,这时候BigDecimal就派上大用场啦。
BIgDecimal的特点
(1)商业计算使用BigDecimal。
(2)尽量使用参数类型为String的构造函数。
(3) BigDecimal都是不可变的(immutable)的,在进行每一步运算时,都会产生一个新的对象,所以在做加减乘除运算时千万要保 存操作后的值。
BigDecimal a = new BigDecimal("4.5");
BigDecimal b = new BigDecimal("1.5");
a.add(b);
System.out.println(a); //输出4.5. 加减乘除方法会返回一个新的BigDecimal对象,原来的a不变
(4)我们往往容易忽略JDK底层的一些实现细节,导致出现错误,需要多加注意。
BigDecimal 构造方法的参数类型问题
先看一下都有哪些构造方法?
BigDecimal一共有4个构造方法:
BigDecimal(int) 创建一个具有参数所指定整数值的对象。
BigDecimal(double) 创建一个具有参数所指定双精度值的对象。(不建议采用)
BigDecimal(long) 创建一个具有参数所指定长整数值的对象。
BigDecimal(String) 创建一个具有参数所指定以字符串表示的数值的对象 [1] 。
//看看这个例子
BigDecimal bdTest = new BigDecimal(1.745);
BigDecimal bdTest1 = new BigDecimal(0.745);
bdTest = bdTest.setScale(2, BigDecimal.ROUND_HALF_UP);
bdTest1 = bdTest1.setScale(2, BigDecimal.ROUND_HALF_UP);
System.out.println("bdTest:" + bdTest); // 1.75
System.out.println("bdTest1:" + bdTest1); // 0.74
System.out.println("=============================");
System.out.println(new BigDecimal(1.745)); // 1.74500000000000010658141036401502788066864013671875
System.out.println(new BigDecimal(0.745)); //0.74499999999999999555910790149937383830547332763671875
看看是什么原因
JDK的描述:
一方面,参数类型为double的构造方法的结果有一定的 **不可预知性** 。有人可能认为在Java中写入newBigDecimal(0.1)
所创建的BigDecimal正好等于 0.1(非标度值 1,其标度为 1),
但是它实际上等于0.1000000000000000055511151231257827021181583404541015625。
这是因为0.1无法准确地表示为 double(或者说对于该情况,不能表示为任何有限长度的二进制小数)。
这样,传入到构造方法的值不会正好等于 0.1(虽然表面上等于该值)。
另一方面,String 构造方法是完全可预知的:写入 newBigDecimal("0.1") 将创建一个 BigDecimal,
它正好等于预期的 0.1。因此,比较而言,通常建议优先使用String构造方法。
字符串不会丢失 使用参数为float或double的BigDecimal创建对象会丢失精度。
因此强烈建议不要使用参数为float或double的BigDecimal创建对象。
当double必须用作BigDecimal的源时,请使用Double.toString(double)转成String,
然后使用String构造方法,或使用BigDecimal的静态方法valueOf,如下
BigDecimal bDouble1 = BigDecimal.valueOf(2.3);
BigDecimal bDouble2 = new BigDecimal(Double.toString(2.3));
System.out.println("bDouble1=" + bDouble1);//2.3
System.out.println("bDouble2=" + bDouble2); //2.3
BigDecimal 的加减乘除
System.out.println("加减乘除:");
BigDecimal a = new BigDecimal("4.5");
BigDecimal b = new BigDecimal("1.5");
System.out.println("a + b =" + a.add(b));
System.out.println("a - b =" + a.subtract(b));
System.out.println("a * b =" + a.multiply(b));
System.out.println("a / b =" + a.divide(b,3,BigDecimal.ROUND_HALF_UP));
这里有一点需要注意的是除法运算divide.
BigDecimal除法可能出现不能整除的情况,比如 4.5/1.3,这时会报错java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
其实divide方法有可以传三个参数
public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)
第一参数表示除数, 第二个参数表示小数点后保留位数, 第三个参数为舍入模式
舍入模式分类
ROUND_DOWN
从不在舍弃(即截断)的小数之前增加数字。
ROUND_UP
总是在非 0 舍弃小数(即截断)之前增加数字。
ROUND_HALF_DOWN
若舍弃部分> .5,则作 ROUND_UP;否则,作 ROUND_DOWN 。
ROUND_HALF_UP
若舍弃部分>=.5,则作 ROUND_UP ;否则,作 ROUND_DOWN 。
ROUND_HALF_EVEN
如果舍弃部分左边的数字为奇数,则作 ROUND_HALF_UP ;如果它为偶数,则作 ROUND_HALF_DOWN 。
ROUND_CEILING
如果 BigDecimal 是正的,则做 ROUND_UP 操作;如果为负,则做 ROUND_DOWN 操作。
ROUND_FLOOR
如果 BigDecimal 为正 则作 ROUND_DOWN , 如果为负,则作 。ROUND_UP
ROUND_UNNECESSARY
该“伪舍入模式”实际是指明所要求的操作必须是精确的,,因此不需要舍入操作。
常用的 四舍五入 ROUND_HALF_UP 截取 ROUND_DOWN
double 或者float 固定小数位数:
double v = new BigDecimal("0.745").setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
BigDecimal bigDecimal = new BigDecimal("0.745").setScale(2,BigDecimal.ROUND_HALF_UP);
文章参考
Java BigDecimal详解
public static void main(String[] args) {
System.out.println("=====================");
// 如果保留位数是奇数,使用ROUND_HALF_UP,如果是偶数,使用ROUND_HALF_DOWN
System.out.println(new BigDecimal("111.12345557")
.setScale(6, BigDecimal.ROUND_HALF_EVEN));//111.123456
}
最后
以上就是内向铃铛为你收集整理的BigDecimal ROUND_HALF_UP 与 ROUND_HALF_DOWN 的区别BigDecimal的全部内容,希望文章能够帮你解决BigDecimal ROUND_HALF_UP 与 ROUND_HALF_DOWN 的区别BigDecimal所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复