BigDecimal BigInteger的使用

1、BigDiCemal

【问题】在项目中,我们进行计算的时候,有时候需要考虑 四舍五入,精度丢失的问题,面对这种问题,我们应该怎么处理?

 System.out.println(0.2+0.1);
 System.out.println(0.3-0.1);
 System.out.println(0.4*0.1);
 System.out.println(0.2+1);

输出结果: 

BigDecimal BigInteger的使用_第1张图片

请忽略 浮点型 与整数的计算。

我们看到上面三个测试 浮点型与浮点型四则运算,运算结果并不是准确的,也不是我们所想要的。

造成这种现象的原因:

因为不论是float 还是double都是浮点数,而计算机是二进制的,浮点数会失去一定的精确度。

注:根本原因是:十进制值通常没有完全相同的二进制表示形式;十进制数的二进制表示形式可能不精确。只能无限接近于那个值。

另外注意一点,整数与浮点数计算,或 整数向浮点数转换的时候,会向下转型。

【怎么解决】

1、简介

java提供了 BigDecimal这个api,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数。在实际应用中,需要对更大或者更小的数进行运算和处理。float和double只能用来做科学计算或者是工程计算,在商业计算中要用java.math.BigDecimal。BigDecimal所创建的是对象,我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象。

2、构造器:

BigDecimal(int)       创建一个具有参数所指定整数值的对象。 

BigDecimal(double) 创建一个具有参数所指定双精度值的对象。 //不推荐使用

BigDecimal(long)    创建一个具有参数所指定长整数值的对象。 

BigDecimal(String) 创建一个具有参数所指定以字符串表示的数值的对象。 推荐使用

这里注意一个问题,对于double 类型的数据,最好不要直接传入BigDecimal构造函数,创建 BigDecimal对象,会出现精度问题,计算错误,建议将double转换成String

比如:

 BigDecimal BigInteger的使用_第2张图片

BigDecimal BigInteger的使用_第3张图片

3、方法描述

add(BigDecimal)        BigDecimal对象中的值相加,然后返回这个对象。 

subtract(BigDecimal) BigDecimal对象中的值相减,然后返回这个对象。 

multiply(BigDecimal)  BigDecimal对象中的值相乘,然后返回这个对象。 

divide(BigDecimal)     BigDecimal对象中的值相除,然后返回这个对象。 

toString()                将BigDecimal对象的数值转换成字符串。 

doubleValue()          将BigDecimal对象中的值以双精度数返回。 

floatValue()             将BigDecimal对象中的值以单精度数返回。 

longValue()             将BigDecimal对象中的值以长整数返回。 

intValue()               将BigDecimal对象中的值以整数返回

在实战中,比较实用的几个方法

stripTrailingZeros():去除尾部所有的0,并返回一个BigDecimal类型的数据,不能保证不是科学计数法。
后加toString()把BigDecimal类型的数据转化成String类型数据,但还是不能保证不是科学计数法。
后加toPlainString()把BigDecimal类型的数据转化成String类型数据,并保证不是科学计数法。

比如上边的例子中,我想去掉最后 1.2000的零

 

除了上述的四则运算,和值输出以外,BigDecimal 更常用的是 取一个数的某一部分,可以是取整数,也可以规定保留的精度

setScale(保留小数点后几位,舍入方法) 

1、UP(BigDecimal.ROUND_UP):远离零方向舍入。向远离0的方向舍入,也就是说,向绝对值最大的方向舍入,只要舍弃位非0即进位。


2、DOWN(BigDecimal.ROUND_DOWN):趋向0方向舍入。向0方向靠拢,也就是说,向绝对值最小的方向输入,注意:所有的位都舍弃,不存在进位情况。


3、CEILING(BigDecimal.ROUND_CEILING):向正无穷方向舍入。向正最大方向靠拢,如果是正数,舍入行为类似于ROUND_UP;如果为负数,则舍入行为类似于ROUND_DOWN.注意:Math.round方法使用的即为此模式。


4、FLOOR(BigDecimal.ROUND_FLOOR):向负无穷方向舍入。向负无穷方向靠拢,如果是正数,则舍入行为类似ROUND_DOWN,如果是负数,舍入行为类似以ROUND_UP。


5、HALF_UP(BigDecimal.ROUND_HALF_UP):最近数字舍入(5舍),这就是我们经典的四舍五入。


6、HALF_DOWN(BigDecimal.ROUND_HALF_DOWN):最近数字舍入(5舍)。在四舍五入中,5是进位的,在HALF_DOWN中却是舍弃不进位。

5.5 -> 5
2.5 -> 2
1.6 -> 2
1.1 -> 1
1.0 -> 1
-1.0 -> -1
-1.1 -> -1
-1.6 -> -2
-2.5 -> -2
-5.5 -> -5

7、HALF_EVEN(BigDecimal.ROUND_HALF_EVEN):银行家算法。四舍六入五考虑,五后非零就进一,五后为零看奇偶,五前为偶应舍去,五前为奇要进一。

5.5 -> 6
2.5 -> 2
1.6 -> 2
1.1 -> 1
1.0 -> 1
-1.0 -> -1
-1.1 -> -1
-1.6 -> -2
-2.5 -> -2
-5.5 -> -6

8、UNNECESSARY(BigDecimal.ROUND_UNNECESSARY):断言请求的操作具有精确的结果,因此不需要舍入。如果对获得精确结果的操作指定此舍入模式,则抛出ArithmeticException。

精确到一位小数点
1.0—>1
1.1抛异常

参考链接:https://blog.csdn.net/xnkjdx105/article/details/124213231

   BigDecimal BigInteger的使用_第4张图片

 BigDecimal BigInteger的使用_第5张图片

所以,我们在面对一般、甚至精确要求非常高的情况下,对小数位进行操作的时候,都可以考虑 BigDecimal

特别是求一个浮点数,保留其后xx位小数的时候,最为可靠。

1)把浮点数转为String   //防止精度丢失

2)调用new BigDecimal(String d),将浮点型转换成更为精确的BigDecimal对象

3) 使用BigDecimal的setScale 方法,求得所需要的精确的结果

对于整形运算,我们为了防止它的结果向下转型,也可以考虑使用Bigdecimal  比如:

BigDecimal BigInteger的使用_第6张图片

 我们日常随意的书写,会造成各种类型转换的隐患,

BigDecimal BigInteger的使用_第7张图片

 输出结果:

2、BigInt

//TODO

你可能感兴趣的:(java,java,开发语言)