关于java:Java中的-BigDecimal80的人都用错了

30次阅读

共计 9355 个字符,预计需要花费 24 分钟才能阅读完成。

一、BigDecimal 概述

Java 在 java.math 包中提供的 API 类 BigDecimal,用来对超过 16 位无效位的数进行准确的运算。双精度浮点型变量 double 能够解决 16 位无效数,但在理论利用中,可能须要对更大或者更小的数进行运算和解决。

个别状况下,对于那些不须要精确计算精度的数字,咱们能够间接应用 Float 和 Double 解决,然而 Double.valueOf(String) 和 Float.valueOf(String)会失落精度。所以开发中,如果咱们须要准确计算的后果,则必须应用 BigDecimal 类来操作。

BigDecimal 所创立的是对象,故咱们不能应用传统的 +、-、*、/ 等算术运算符间接对其对象进行数学运算,而必须调用其绝对应的办法。办法中的参数也必须是 BigDecimal 的对象。结构器是类的非凡办法,专门用来创建对象,特地是带有参数的对象。

二、BigDecimal 罕用构造函数

2.1、罕用构造函数

BigDecimal(int)
创立一个具备参数所指定整数值的对象

BigDecimal(double)
创立一个具备参数所指定双精度值的对象

BigDecimal(long)
创立一个具备参数所指定长整数值的对象

BigDecimal(String)
创立一个具备参数所指定以字符串示意的数值的对象

2.2、应用问题剖析
应用示例:

BigDecimal a =new BigDecimal(0.1);  
System.out.println("a values is:"+a);  
System.out.println("=====================");  
BigDecimal b =new BigDecimal("0.1");  
System.out.println("b values is:"+b);  

后果示例:

a values is:0.1000000000000000055511151231257827021181583404541015625  
=====================  
b values is:0.1  

起因剖析:

1)参数类型为 double 的构造方法的后果有肯定的不可预知性。有人可能认为在 Java 中写入 newBigDecimal(0.1)所创立的 BigDecimal 正好等于 0.1(非标度值 1,其标度为 1),然而它实际上等于 0.1000000000000000055511151231257827021181583404541015625。这是因为 0.1 无奈精确地示意为 double(或者说对于该状况,不能示意为任何无限长度的二进制小数)。这样,传入到构造方法的值不会正好等于 0.1(尽管外表上等于该值)。

2)String 构造方法是齐全可预知的:写入 newBigDecimal(“0.1”) 将创立一个 BigDecimal,它正好等于预期的 0.1。因而,比较而言,通常倡议优先应用 String 构造方法。

3)当 double 必须用作 BigDecimal 的源时,请留神,此构造方法提供了一个精确转换;它不提供与以下操作雷同的后果:先应用 Double.toString(double)办法,而后应用 BigDecimal(String)构造方法,将 double 转换为 String。要获取该后果,请应用 static valueOf(double)办法。

三、BigDecimal 罕用办法详解
3.1、罕用办法

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 对象中的值转换成整数

3.2、BigDecimal 大小比拟

java 中对 BigDecimal 比拟大小个别用的是 bigdemical 的 compareTo 办法

int a = bigdemical.compareTo(bigdemical2)  

返回后果剖析:

a = -1, 示意 bigdemical 小于 bigdemical2;a = 0, 示意 bigdemical 等于 bigdemical2;a = 1, 示意 bigdemical 大于 bigdemical2;

举例:a 大于等于 b

new bigdemica(a).compareTo(new bigdemical(b)) >= 0  

四、BigDecimal 格式化

因为 NumberFormat 类的 format()办法能够应用 BigDecimal 对象作为其参数,能够利用 BigDecimal 对超出 16 位有效数字的货币值,百分值,以及个别数值进行格式化管制。

以利用 BigDecimal 对货币和百分比格式化为例。首先,创立 BigDecimal 对象,进行 BigDecimal 的算术运算后,别离建设对货币和百分比格式化的援用,最初利用 BigDecimal 对象作为 format()办法的参数,输入其格式化的货币值和百分比。

NumberFormat currency = NumberFormat.getCurrencyInstance(); // 建设货币格式化援用   
NumberFormat percent = NumberFormat.getPercentInstance();  // 建设百分比格式化援用   
percent.setMaximumFractionDigits(3); // 百分比小数点最多 3 位   
  
BigDecimal loanAmount = new BigDecimal("15000.48"); // 贷款金额  
BigDecimal interestRate = new BigDecimal("0.008"); // 利率     
BigDecimal interest = loanAmount.multiply(interestRate); // 相乘  
  
System.out.println("贷款金额:\t" + currency.format(loanAmount));   
System.out.println("利率:\t" + percent.format(interestRate));   
System.out.println("利息:\t" + currency.format(interest));   

后果:
贷款金额: ¥15,000.48 利率: 0.8% 利息: ¥120.00
BigDecimal 格式化保留 2 为小数,有余则补 0:

public class NumberFormat {public static void main(String[] s){System.out.println(formatToNumber(new BigDecimal("3.435")));  
        System.out.println(formatToNumber(new BigDecimal(0)));  
        System.out.println(formatToNumber(new BigDecimal("0.00")));  
        System.out.println(formatToNumber(new BigDecimal("0.001")));  
        System.out.println(formatToNumber(new BigDecimal("0.006")));  
        System.out.println(formatToNumber(new BigDecimal("0.206")));  
    }  
    /**  
     * @desc 1.0~1 之间的 BigDecimal 小数,格式化后失去后面的 0, 则后面间接加上 0。* 2. 传入的参数等于 0,则间接返回字符串 "0.00"  
     * 3. 大于 1 的小数,间接格式化返回字符串  
     * @param obj 传入的小数  
     * @return  
     */  
    public static String formatToNumber(BigDecimal obj) {DecimalFormat df = new DecimalFormat("#.00");  
        if(obj.compareTo(BigDecimal.ZERO)==0) {return "0.00";}else if(obj.compareTo(BigDecimal.ZERO)>0&&obj.compareTo(new BigDecimal(1))<0){return "0"+df.format(obj).toString();}else {return df.format(obj).toString();}  
    }  
}  

后果为:

3.44  
0.00  
0.00  
0.00  
0.01  
0.21  

五、BigDecimal 常见异样

5.1、除法的时候出现异常
java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result

起因剖析:

通过 BigDecimal 的 divide 办法进行除法时当不整除,呈现有限循环小数时,就会抛异样:java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.

解决办法:

divide 办法设置准确的小数点,如:divide(xxxxx,2)

六、BigDecimal 总结

6.1、总结
在须要准确的小数计算时再应用 BigDecimal,BigDecimal 的性能比 double 和 float 差,在解决宏大,简单的运算时尤为显著。故个别精度的计算没必要应用 BigDecimal。
尽量应用参数类型为 String 的构造函数。

BigDecimal 都是不可变的(immutable)的,在进行每一次四则运算时,都会产生一个新的对象,所以在做加减乘除运算时要记得要保留操作后的值。

6.2、工具类举荐

package com.vivo.ars.util;  
import java.math.BigDecimal;  
  
/**  
 * 用于高准确解决罕用的数学运算  
 */  
public class ArithmeticUtils {  
    // 默认除法运算精度  
    private static final int DEF_DIV_SCALE = 10;  
  
    /**  
     * 提供准确的加法运算  
     *  
     * @param v1 被加数  
     * @param v2 加数  
     * @return 两个参数的和  
     */  
  
    public static double add(double v1, double v2) {BigDecimal b1 = new BigDecimal(Double.toString(v1));  
        BigDecimal b2 = new BigDecimal(Double.toString(v2));  
        return b1.add(b2).doubleValue();}  
  
    /**  
     * 提供准确的加法运算  
     *  
     * @param v1 被加数  
     * @param v2 加数  
     * @return 两个参数的和  
     */  
    public static BigDecimal add(String v1, String v2) {BigDecimal b1 = new BigDecimal(v1);  
        BigDecimal b2 = new BigDecimal(v2);  
        return b1.add(b2);  
    }  
  
    /**  
     * 提供准确的加法运算  
     *  
     * @param v1    被加数  
     * @param v2    加数  
     * @param scale 保留 scale 位小数  
     * @return 两个参数的和  
     */  
    public static String add(String v1, String v2, int scale) {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.add(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();}  
  
    /**  
     * 提供准确的减法运算  
     *  
     * @param v1 被减数  
     * @param v2 减数  
     * @return 两个参数的差  
     */  
    public static double sub(double v1, double v2) {BigDecimal b1 = new BigDecimal(Double.toString(v1));  
        BigDecimal b2 = new BigDecimal(Double.toString(v2));  
        return b1.subtract(b2).doubleValue();}  
  
    /**  
     * 提供准确的减法运算。*  
     * @param v1 被减数  
     * @param v2 减数  
     * @return 两个参数的差  
     */  
    public static BigDecimal sub(String v1, String v2) {BigDecimal b1 = new BigDecimal(v1);  
        BigDecimal b2 = new BigDecimal(v2);  
        return b1.subtract(b2);  
    }  
  
    /**  
     * 提供准确的减法运算  
     *  
     * @param v1    被减数  
     * @param v2    减数  
     * @param scale 保留 scale 位小数  
     * @return 两个参数的差  
     */  
    public static String sub(String v1, String v2, int scale) {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.subtract(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();}  
  
    /**  
     * 提供准确的乘法运算  
     *  
     * @param v1 被乘数  
     * @param v2 乘数  
     * @return 两个参数的积  
     */  
    public static double mul(double v1, double v2) {BigDecimal b1 = new BigDecimal(Double.toString(v1));  
        BigDecimal b2 = new BigDecimal(Double.toString(v2));  
        return b1.multiply(b2).doubleValue();}  
  
    /**  
     * 提供准确的乘法运算  
     *  
     * @param v1 被乘数  
     * @param v2 乘数  
     * @return 两个参数的积  
     */  
    public static BigDecimal mul(String v1, String v2) {BigDecimal b1 = new BigDecimal(v1);  
        BigDecimal b2 = new BigDecimal(v2);  
        return b1.multiply(b2);  
    }  
  
    /**  
     * 提供准确的乘法运算  
     *  
     * @param v1    被乘数  
     * @param v2    乘数  
     * @param scale 保留 scale 位小数  
     * @return 两个参数的积  
     */  
    public static double mul(double v1, double v2, int scale) {BigDecimal b1 = new BigDecimal(Double.toString(v1));  
        BigDecimal b2 = new BigDecimal(Double.toString(v2));  
        return round(b1.multiply(b2).doubleValue(), scale);  
    }  
  
    /**  
     * 提供准确的乘法运算  
     *  
     * @param v1    被乘数  
     * @param v2    乘数  
     * @param scale 保留 scale 位小数  
     * @return 两个参数的积  
     */  
    public static String mul(String v1, String v2, int scale) {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.multiply(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();}  
  
    /**  
     * 提供(绝对)准确的除法运算,当产生除不尽的状况时,准确到  
     * 小数点当前 10 位,当前的数字四舍五入  
     *  
     * @param v1 被除数  
     * @param v2 除数  
     * @return 两个参数的商  
     */  
  
    public static double div(double v1, double v2) {return div(v1, v2, DEF_DIV_SCALE);  
    }  
  
    /**  
     * 提供(绝对)准确的除法运算。当产生除不尽的状况时,由 scale 参数指  
     * 定精度,当前的数字四舍五入  
     *  
     * @param v1    被除数  
     * @param v2    除数  
     * @param scale 示意示意须要准确到小数点当前几位。* @return 两个参数的商  
     */  
    public static double div(double v1, double v2, int scale) {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, BigDecimal.ROUND_HALF_UP).doubleValue();}  
  
    /**  
     * 提供(绝对)准确的除法运算。当产生除不尽的状况时,由 scale 参数指  
     * 定精度,当前的数字四舍五入  
     *  
     * @param v1    被除数  
     * @param v2    除数  
     * @param scale 示意须要准确到小数点当前几位  
     * @return 两个参数的商  
     */  
    public static String div(String v1, String v2, int scale) {if (scale < 0) {throw new IllegalArgumentException("The scale must be a positive integer or zero");  
        }  
        BigDecimal b1 = new BigDecimal(v1);  
        BigDecimal b2 = new BigDecimal(v1);  
        return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).toString();}  
  
    /**  
     * 提供准确的小数位四舍五入解决  
     *  
     * @param v     须要四舍五入的数字  
     * @param scale 小数点后保留几位  
     * @return 四舍五入后的后果  
     */  
    public static double round(double v, int scale) {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, BigDecimal.ROUND_HALF_UP).doubleValue();}  
  
    /**  
     * 提供准确的小数位四舍五入解决  
     *  
     * @param v     须要四舍五入的数字  
     * @param scale 小数点后保留几位  
     * @return 四舍五入后的后果  
     */  
    public static String round(String v, int scale) {if (scale < 0) {  
            throw new IllegalArgumentException("The scale must be a positive integer or zero");  
        }  
        BigDecimal b = new BigDecimal(v);  
        return b.setScale(scale, BigDecimal.ROUND_HALF_UP).toString();}  
  
    /**  
     * 取余数  
     *  
     * @param v1    被除数  
     * @param v2    除数  
     * @param scale 小数点后保留几位  
     * @return 余数  
     */  
    public static String remainder(String v1, String v2, int scale) {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.remainder(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();}  
  
    /**  
     * 取余数  BigDecimal  
     *  
     * @param v1    被除数  
     * @param v2    除数  
     * @param scale 小数点后保留几位  
     * @return 余数  
     */  
    public static BigDecimal remainder(BigDecimal v1, BigDecimal v2, int scale) {if (scale < 0) {  
            throw new IllegalArgumentException("The scale must be a positive integer or zero");  
        }  
        return v1.remainder(v2).setScale(scale, BigDecimal.ROUND_HALF_UP);  
    }  
  
    /**  
     * 比拟大小  
     *  
     * @param v1 被比拟数  
     * @param v2 比拟数  
     * @return 如果 v1 大于 v2 则 返回 true 否则 false  
     */  
    public static boolean compare(String v1, String v2) {BigDecimal b1 = new BigDecimal(v1);  
        BigDecimal b2 = new BigDecimal(v2);  
        int bj = b1.compareTo(b2);  
        boolean res;  
        if (bj > 0)  
            res = true;  
        else  
            res = false;  
        return res;  
    }  
}

以上并是全副的内容,心愿能帮忙到大家!

正文完
 0