您的位置:首页 > 编程语言 > Java开发

Java中使用Bigdecimal类型进行精确商业计算

2017-05-27 00:06 323 查看
java的float和double只能用来进行科学计算或工程计算,在大多数的商业计算中,一般采用java.math.BigDecimal类来进行精确计算。大数据类型 java.math.BigDecimal ,该类型的数据精度极高,适合做财务软件。

原因在于我们的计算机是二进制的。浮点数没有办法使用二进制进行精确表示。我们的CPU表示浮点数由两个部分组成:指数和尾数,这样的表示方法一般都会失去一定的精确度,有些浮点数运算也会产生一定的误差。如:2.4的二进制表示并非就是精确的2.4。反而最为接近的二进制表示是 2.3999999999999999。浮点数的值实际上是由一个特定的数学公式计算得到的。

BigDecimal中的舍入模式介绍:

舍入模式:RoundingMode中的舍入模式和BigDecimal中的舍入模式是一样的,比如RoundingMode.*相当于BigDecimal.ROUND_*

ROUND_CEILING :向正无限大方向舍入的舍入模式。如果结果为正,则舍入行为类似于 RoundingMode.UP;如果结果为负,则舍入行为类似于 RoundingMode.DOWN。注意,此舍入模式始终不会减少计算值


[b]ROUND_DOWN[/b] :向零方向舍入的舍入模式。从不对舍弃部分前面的数字加 1(即截尾)。注意,此舍入模式始终不会增加计算值的绝对值

[b]ROUND_FLOOR[/b] :向负无限大方向舍入的舍入模式。如果结果为正,则舍入行为类似于 RoundingMode.DOWN;如果结果为负,则舍入行为类似于 RoundingMode.UP。注意,此舍入模式始终不会增加计算值

[b]ROUND_UNNECESSARY[/b] :用于断言请求的操作具有精确结果的舍入模式,因此不需要舍入。如果对生成精确结果的操作指定此舍入模式,则抛出 ArithmeticException

[b]ROUND_UP[/b] :远离零方向舍入的舍入模式。始终对非零舍弃部分前面的数字加 1。注意,此舍入模式始终不会减少计算值的绝对值

[b]ROUND_HALF_DOWN[/b] :向最接近数字方向舍入的舍入模式,如果与两个相邻数字的距离相等,则向下舍入。如果被舍弃部分 > 0.5,则舍入行为同 RoundingMode.UP;否则舍入行为同 RoundingMode.DOWN

[b]ROUND_HALF_EVEN[/b] :向 最接近数字方向舍入的舍入模式,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。如果舍弃部分左边的数字为奇数,则舍入行为同 RoundingMode.HALF_UP;如果为偶数,则舍入行为同 RoundingMode.HALF_DOWN。注意,在重复进行一系列计算时,此舍入模式可以在统计上将累加错误减到最小。此舍入模式也称为“银行家舍入法”,主要在美国使用。此舍入模式类似于 Java 中对 float 和 double 算法使用的舍入策略

[b]ROUND_HALF_UP[/b] :向最接近数字方向舍入的舍入模式,如果与两个相邻数字的距离相等,则向上舍入。如果被舍弃部分 >= 0.5,则舍入行为同 RoundingMode.UP;否则舍入行为同 RoundingMode.DOWN。注意,此舍入模式就是通常学校里讲的四舍五入

工具类:

1 import java.math.BigDecimal;
2
3 public class BigDecimalUtil {
4
5     /**
6      * 提供精确加法计算的add方法
7      * @param value1 被加数
8      * @param value2 加数
9      * @return 两个参数的和
10      */
11     public static double add(double value1,double value2){
12         BigDecimal b1 = new BigDecimal(Double.valueOf(value1));
13         BigDecimal b2 = new BigDecimal(Double.valueOf(value2));
14         return b1.add(b2).doubleValue();
15     }
16
17     /**
18      * 提供精确减法运算的sub方法
19      * @param value1 被减数
20      * @param value2 减数
21      * @return 两个参数的差
22      */
23     public static double sub(double value1,double value2){
24         BigDecimal b1 = new BigDecimal(Double.valueOf(value1));
25         BigDecimal b2 = new BigDecimal(Double.valueOf(value2));
26         return b1.subtract(b2).doubleValue();
27     }
28
29     /**
30      * 提供精确乘法运算的mul方法
31      * @param value1 被乘数
32      * @param value2 乘数
33      * @return 两个参数的积
34      */
35     public static double mul(double value1,double value2){
36         BigDecimal b1 = new BigDecimal(Double.valueOf(value1));
37         BigDecimal b2 = new BigDecimal(Double.valueOf(value2));
38         return b1.multiply(b2).doubleValue();
39     }
40
41     /**
42      * 提供(相对)精确的除法运算div方法,当发生除不尽的情况时,由 scale 参数指定精度,其后的数字四舍五入。
43      * @param value1 被除数
44      * @param value2 除数
45      * @param scale 精确范围,小数点后保留几位
46      * @return 两个参数的商
47      * @throws IllegalAccessException
48      */
49     public static double div(double value1,double value2,int scale) throws IllegalAccessException{
50         //如果精确范围小于0,抛出异常信息
51         if(scale < 0){
52             throw new IllegalAccessException("精确度不能小于0");
53         }
54         BigDecimal b1 = new BigDecimal(Double.valueOf(value1));
55         BigDecimal b2 = new BigDecimal(Double.valueOf(value2));
56         return b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
57     }
58
59     /**
60      * 提供精确的小数位四舍五入处理。
61      * @param value 需要四舍五入的数字
62      * @param scale 精确范围,小数点后保留几位
63      * @return 四舍五入后的结果
64      * @throws IllegalAccessException
65      */
66     public static double round(double value, int scale) throws IllegalAccessException{
67         //如果精确范围小于0,抛出异常信息
68         if(scale<0){
69             throw new IllegalAccessException("精确度不能小于0");
70         }
71         BigDecimal b = new BigDecimal(Double.toString(value));
72         BigDecimal one = new BigDecimal("1");
73         return b.divide(one,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
74     }
75
76 }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: