<导航

BigDecimal用法

一、简介

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

二、常用方法

add(BigDecimal)                //BigDecimal对象中的值相加,然后返回BigDecimal对象
subtract(BigDecimal)        //BigDecimal对象中的值相减,然后返回BigDecimal对象
multiply(BigDecimal)        //BigDecimal对象中的值相乘,然后返回BigDecimal对象
divide(BigDecimal)            //BigDecimal对象中的值相除,然后返回BigDecimal对象
toString()            //将BigDecimal对象的数值转换成字符串
doubleValue()        //将BigDecimal对象中的值以双精度数返回
floatValue()        //将BigDecimal对象中的值以单精度数返回
longValue()            //将BigDecimal对象中的值以长整数返回
intValue()            //将BigDecimal对象中的值以整数返回

三、NumberFormat类的format()方法格式化

   由于NumberFormat类的format()方法可以使用BigDecimal对象作为其参数,可以利用BigDecimal对超出16位有效数字的货币值,百分值,以及一般数值进行格式化控制。

/** 
 * 格式化 
 */  
@Test  
public void test3() {  
    NumberFormat currency = NumberFormat.getCurrencyInstance(); //建立货币格式化引用  
    NumberFormat percent = NumberFormat.getPercentInstance();  //建立百分比格式化引用  
    percent.setMaximumFractionDigits(3); //百分比小数点最多3位  
  
    BigDecimal loanAmount = new BigDecimal("150.48"); //贷款金额  
    BigDecimal interestRate = new BigDecimal("0.008"); //利率  
    BigDecimal interest = loanAmount.multiply(interestRate); //相乘  
  
    System.out.println("贷款金额:\t" + currency.format(loanAmount)); //贷款金额: ¥150.48  
    System.out.println("利率:\t" + percent.format(interestRate));  //利率: 0.8%  
    System.out.println("利息:\t" + currency.format(interest)); //利息: ¥1.20  
}

四、BigDecimal比较大小

/** 
 * 注意不能使用equals方法来比较大小。 
 * 
 * 使用BigDecimal的坏处是性能比double和float差,在处理庞大,复杂的运算时尤为明显,因根据实际需求决定使用哪种类型。 
 */  
@Test  
public void test4() {  
    BigDecimal a = new BigDecimal("1");  
    BigDecimal b = new BigDecimal("6");  
    BigDecimal c = new BigDecimal("1");  
    int result1 = a.compareTo(b);  
    int result2 = a.compareTo(c);  
    int result3 = b.compareTo(a);  
  
    System.out.println(result1);  //-1  
    System.out.println(result2);  //0  
    System.out.println(result3);  //1  
}  

五、科学计数法

  有些项目可能会涉及到从Excel导入数据,但如果Excel里单元格类型为数值,但内容数据太长时(如银行账号),导入时,会默认读取为科学计数法,用以下代码便轻松解决。

@Test  
public void test5() {  
    BigDecimal bd = new BigDecimal("3.40256010353E11");  
    String result = bd.toPlainString();  
    System.out.println(result);  //340256010353  
} 

六、精确计算

众所周知,java在浮点型运算时是非精确计算,如下demo

System.out.println(0.05 + 0.01);// 0.060000000000000005
System.out.println(1.0 - 0.42);// 0.5800000000000001
System.out.println(4.015 * 100);// 401.49999999999994
System.out.println(123.3 / 100);// 1.2329999999999999

在商业运算中,这点微小的误差有可能造成非常严重的后果。 
所以在商业应用开发中,涉及金额等浮点数计算的数据,全部使用BigDecimal进行加减乘除计算。

double value1=1.00;  
String value2 = "1.00";  
BigDecimal b1 = new BigDecimal(Double.valueOf(value1));  
BigDecimal b1 = new BigDecimal(String.valueOf(value2));  
  
 public BigDecimal add(BigDecimal value);                        //加法  
 public BigDecimal subtract(BigDecimal value);                   //减法   
 public BigDecimal multiply(BigDecimal value);                   //乘法  
 public BigDecimal divide(BigDecimal value);                     //除法  

七、BigDecimal 舍入模式(Rounding mode)介绍:

ROUND_CEILING:向正无穷方向舍入

ROUND_DOWN:向零方向舍入

ROUND_FLOOR:向负无穷方向舍入

ROUND_HALF_DOWN:向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,向下舍入, 例如1.55 保留一位小数结果为1.5

ROUND_HALF_EVEN:向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,如果保留位数是奇数,使用: : ROUND_HALF_DOWN如果是偶数,使用ROUND_HALF_UP

ROUND_HALF_UP:向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,向上舍入, 1.55保留一位小数结果为1.6

ROUND_UP:向远离0的方向舍入

ROUND_UNNECESSARY:计算结果是精确的,不需要舍入模式

八、BigDecimal工具类

import java.math.BigDecimal;
public class BigDecimalUtil {
    // 默认除法运算精度
    private static final int DEFAULT_DIV_SCALE = 5;

    /**
     * 提供精确的加法运算
     * 
     * @param v1
     * @param v2
     * @return
     */
    public static double add(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.add(b2).doubleValue();
    }

    public static String add(String v1, String v2) {
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.add(b2).toString();
    }

    /**
     * 提供精确的减法运算
     * 
     * @param v1
     * @param v2
     * @return
     */
    public static double subtract(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.subtract(b2).doubleValue();
    }

    public static String substract(String v1, String v2) {
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.subtract(b2).toString();
    }

    /**
     * 提供精确的乘法运算
     * 
     * @param v1
     * @param v2
     * @return
     */
    public static double multiply(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.multiply(b2).doubleValue();
    }

    public static String multiply(String v1, String v2) {
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.multiply(b2).toString();
    }

    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 小数点以后10位,以后的数字四舍五入,舍入模式采用ROUND_HALF_UP
     * 
     * @param v1
     * @param v2
     * @return 两个参数的商
     */
    public static double divide(double v1, double v2) {
        return divide(v1, v2, DEFAULT_DIV_SCALE);
    }

    /**
     * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 定精度,以后的数字四舍五入。舍入模式采用ROUND_HALF_UP
     * 
     * @param v1
     * @param v2
     * @param scale
     *            表示需要精确到小数点以后几位。
     * @return 两个参数的商
     */
    public static double divide(double v1, double v2, int scale) {
        return divide(v1, v2, scale, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 定精度,以后的数字四舍五入。舍入模式采用用户指定舍入模式
     * 
     * @param v1
     * @param v2
     * @param scale
     *            表示需要精确到小数点以后几位
     * @param round_mode
     *            表示用户指定的舍入模式
     * @return 两个参数的商
     */
    public static double divide(double v1, double v2, int scale, int round_mode) {
        if (scale < 0) {
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.divide(b2, scale, round_mode).doubleValue();
    }

    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 小数点以后10位,以后的数字四舍五入,舍入模式采用ROUND_HALF_EVEN
     * 
     * @param v1
     * @param v2
     * @return 两个参数的商,以字符串格式返回
     */
    public static String divide(String v1, String v2) {
        return divide(v1, v2, DEFAULT_DIV_SCALE);
    }

    /**
     * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 定精度,以后的数字四舍五入。舍入模式采用ROUND_HALF_UP
     * 
     * @param v1
     * @param v2
     * @param scale
     *            表示需要精确到小数点以后几位
     * @return 两个参数的商,以字符串格式返回
     */
    public static String divide(String v1, String v2, int scale) {
        return divide(v1, v2, scale, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 定精度,以后的数字四舍五入。舍入模式采用用户指定舍入模式
     * 
     * @param v1
     * @param v2
     * @param scale
     *            表示需要精确到小数点以后几位
     * @param round_mode
     *            表示用户指定的舍入模式
     * @return 两个参数的商,以字符串格式返回
     */
    public static String divide(String v1, String v2, int scale, int round_mode) {
        if (scale < 0) {
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.divide(b2, scale, round_mode).toString();
    }

    /**
     * 提供精确的小数位四舍五入处理,舍入模式采用ROUND_HALF_EVEN
     * 
     * @param v
     *            需要四舍五入的数字
     * @param scale
     *            小数点后保留几位
     * @return 四舍五入后的结果
     */
    public static double round(double v, int scale) {
        return round(v, scale, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 提供精确的小数位四舍五入处理
     * 
     * @param v
     *            需要四舍五入的数字
     * @param scale
     *            小数点后保留几位
     * @param round_mode
     *            指定的舍入模式
     * @return 四舍五入后的结果
     */
    public static double round(double v, int scale, int round_mode) {
        if (scale < 0) {
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        BigDecimal b = new BigDecimal(Double.toString(v));
        return b.setScale(scale, round_mode).doubleValue();
    }

    /**
     * 提供精确的小数位四舍五入处理,舍入模式采用ROUND_HALF_UP
     * 
     * @param v
     *            需要四舍五入的数字
     * @param scale
     *            小数点后保留几位
     * @return 四舍五入后的结果,以字符串格式返回
     */
    public static String round(String v, int scale) {
        return round(v, scale, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 提供精确的小数位四舍五入处理
     * 
     * @param v
     *            需要四舍五入的数字
     * @param scale
     *            小数点后保留几位
     * @param round_mode
     *            指定的舍入模式
     * @return 四舍五入后的结果,以字符串格式返回
     */
    public static String round(String v, int scale, int round_mode) {
        if (scale < 0) {
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        BigDecimal b = new BigDecimal(v);
        return b.setScale(scale, round_mode).toString();
    }
}
View Code

九、java保留两位小数的方法

 1 import java.math.BigDecimal;
 2 import java.text.DecimalFormat;
 3 import java.text.NumberFormat;
 4 public class NumberFormatDemo {
 5     public static void main(String[] args) {
 6         // BigDecimal
 7         // 保留两位小数
 8         System.out.println(new BigDecimal(0.2).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());// 0.2
 9         System.out.println(new BigDecimal(0.235).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());// 0.23
10         System.out.println(new BigDecimal(0.2351).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());// 0.24
11         System.out.println(new BigDecimal(42).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());// 42.0
12 
13         // NumberFormat
14         // 保留两位小数,个位无数字填充0
15         NumberFormat nformat = NumberFormat.getNumberInstance();
16         nformat.setMaximumFractionDigits(2);
17         System.out.println(nformat.format(0.2));// 0.2
18         System.out.println(nformat.format(0.235));// 0.23
19         System.out.println(nformat.format(0.2351));// 0.24
20         System.out.println(nformat.format(42));// 42
21 
22         // DecimalFormat,是NumberFormat的具体实现子类
23         // 保留两位小数,对应位上无数字填充0
24         DecimalFormat df = new DecimalFormat("#0.00");
25         System.out.println(df.format(0.2));// 0.20
26         System.out.println(df.format(0.235));// 0.23
27         System.out.println(df.format(0.2351));// 0.2, 因为0.2351在0.23-0.24之间,距离0.24更近,所以输出0.24
28         System.out.println(df.format(42));// 42.00
29 
30         DecimalFormat df4 = new DecimalFormat();
31         // #:位置上无数字不显示
32         df4.applyPattern("#.##");
33         System.out.println(df4.format(345235.0));// 345235
34         // 0:位置上无数字显示0
35         df4.applyPattern("0.00");
36         System.out.println(df4.format(345235.0));// 345235.00
37         // 加负数显示
38         df4.applyPattern("-0.00");
39         System.out.println(df4.format(345235.34567));// -345235.35
40         // 逗号分隔
41         df4.applyPattern("-0,000.00");
42         System.out.println(df4.format(345235.34567));// -345,235.35
43         // 百分位
44         df4.applyPattern("0.00%");
45         System.out.println(df4.format(0.34567));// 34.57%
46         // 千分位
47         df4.applyPattern("0.00\u2030");
48         System.out.println(df4.format(0.34567));// 345.67‰
49         // 科学计数法,E之前是底数的格式,E之后的是指数的格式
50         df4.applyPattern("0.00E00");
51         System.out.println(df4.format(2342.444));// 2.34E03
52         // 格式后面加单位符号
53         df4.applyPattern("0.00 KG");
54         System.out.println(df4.format(2342.444));// 2342.44 KG
55         df4.applyPattern("0.00 QA");
56         System.out.println(df4.format(2342.444));// 2342.44 QA
57         // 使用舍入模式:ROUND_HALF_EVEN,
58         // 保留位数是奇数,使用ROUND_HALF_DOWN
59         // 保留位数是偶数,使用ROUND_HALF_UP
60         System.out.println(df4.format(2342.435));// 2342.43 QA
61         System.out.println(df4.format(2342.445));// 2342.45 QA
62 
63         // String.format
64         // 保留两位小数,个位数及小数点后两位无数字填充0,四舍五入
65         System.out.println(String.format("%.2f", 0.2));// 0.20
66         System.out.println(String.format("%.2f", 0.235));// 0.24
67         System.out.println(String.format("%.2f", 0.236));// 0.24
68         System.out.println(String.format("%.2f", 42.0));// 42.00
69     }
70 }
View Code

 

参考文章:

https://blog.csdn.net/mglgcx/article/details/78560029?locationNum=10&fps=1

https://www.cnblogs.com/jpfss/p/8072379.html#

 

posted @ 2018-11-13 18:12  字节悦动  阅读(204)  评论(0编辑  收藏  举报