本文主要介绍java BigDecimal的精度。对精确计算感兴趣的同学可以参考一下。
一.背景二BigDecimal构造函数1。四个构造者2。为什么会这样3。如何解决3。常用方法1。常用方法2。选择规则4。格式化
目录
在实际开发中,对于不需要任何精确计算精度的属性,可以直接使用float或double,但是如果需要精确的计算结果,就必须使用BigDecimal,比如价格和质量。
为什么这么说?主要有两点。
1.双重计算会有精度损失的问题。
2.BigDecimal提供了丰富的除法选择规则。(double可以被NumberFormat舍入,但是NumberFormat是线程不安全的)
对于精度问题,可以看实际例子。
公共静态void main(String[] args) {
//正常3.3
System.out.println('加法结果:'(1.1 2.2));
//正常-7.9
System.out.println('减法结果:'(2.2-10.1));
//正常2.42
System.out.println('乘法结果:'(1.1 * 2.2));
//正常0.44
System.out.println('除法结果:'(4.4/10));
}
实际控制台输出
为什么
我们的计算机是二进制的。没有办法用二进制精确地表示浮点数。我们的CPU指出浮点数由两部分组成:指数和尾数,这种表示通常
没有一定的准确度,一些浮点数运算也会产生一定的误差。例如,2.4的二进制表示并不完全是2.4。相反,最接近的二进制表示法是2。46860 . 66868686861
浮点数的值实际上是由特定的数学公式计算出来的。
一、背景
二、BigDecimal构造函数
BigDecimal(int)///用参数指定的整数值创建一个对象。
BigDecimal(double)///使用参数指定的double值创建一个对象。
BigDecimal(long)///使用参数指定的长整型值创建一个对象。
BigDecimal(String)///用参数指定的数值作为字符串创建一个对象。
这些是常用的构造函数,它们返回的对象是BigDecimal对象。换句话说,我们可以通过以下方法将BigDecimal对象转换成其他类型的对象。
string()//将BigDecimal对象的数值转换为字符串。
DoubleValue() //以双精度形式返回BigDecimal对象中的值。
FloatValue() //以单精度数字形式返回BigDecimal对象中的值。
LongValue() //以长整型返回BigDecimal对象中的值。
IntValue() //以整数形式返回BigDecimal对象中的值。
这里需要非常注意BigDecimal(double)的构造函数,会有精度损失的问题,其他的不会。这里,我们可以举个例子。
公共静态void main(String[] args) {
BigDecimal int decimal=new BigDecimal(10);
BigDecimal double decimal=new BigDecimal(4.3);
BigDecimal long decimal=new BigDecimal(10L);
BigDecimal string decimal=new BigDecimal(' 4.3 ');
system . out . println(' int decimal=' int decimal);
system . out . println(' double decimal=' double decimal);
system . out . println(' long decimal=' long decimal);
system . out . println(' string decimal=' string decimal);
}
控制台的实际输出
从图中可以明显看出,对于双重构造函数来说,存在精度损失的可能性。
1、四种构造函数
解释了新的BigDecimal(double)类型的构造函数上的注释。
这个构造函数的结果可能有些不可预测。假设你可以用Java写new BigDecimal(0.1)来创建一个BigDecimal,它完全等于0.1(非小数数值为1,小数数值为1),但实际上等于
0.1000000000000000055511151231257827021181583404541015625。这是因为0.1无法像double(或任何有限长度的二进制分数)那样精确地表示。
因此,传递给构造的值不完全等于0.1。
2、为什么会出现这种情况
有两种常见的解决方案。
1、是将两倍通过Double.toString(double)先转为字符串,然后放入BigDecimal的线构造函数中。
2、不通过BigDecimal的构造函数,而是通过它的静态方法BigDecimal.valueOf(double),也同样不会丢失精度。
示例
公共静态void main(String[] args) {
string string=double。tostring(4.3);
BigDecimal string BigDecimal=new BigDecimal(string);
BigDecimal=BigDecimal。(4.3)的值;
系统。出去。println(' stringBigDecimal=' stringBigDecimal);
系统。出去。println(' bigDecimal=' bigDecimal);
}
运行结果
这样也能保证,对与两倍而言,转BigDecimal不会出现精度丢失的情况。
3、如何解决
三、常用方法
示例
公共静态void main(String[] args) {
BigDecimal a=new BigDecimal(' 4.5 ');
BigDecimal b=new BigDecimal(' 1.5 ');
BigDecimal c=new BigDecimal('-10.5 ');
BigDecimal add _ result=a . add(b);
BigDecimal subtract _ result=a . subtract(b);
BigDecimal multiply _ result=a . multiply(b);
BigDecimal divide _ result=a . divide(b);
BigDecimal reminder _ result=a . reminder(b);
BigDecimal max _ result=a . max(b);
BigDecimal min _ result=a . min(b);
BigDecimal ABS _ result=c . ABS();
BigDecimal negate _ result=a . negate();
系统。出去。println(' 4.5 1.5=' add _ result);
系统。出去。println(' 4.5-1.5=' subtract _ result);
系统。出去。println(' 4.5 * 1.5=' multiply _ result);
系统。出去。println(' 4.5/1.5=' divide _ result);
System.out.println('4.5/1.5余数=' remainder _ result);
System.out.println('4.5和1.5最大数=' max _ result);
System.out.println('4.5和1.5最小数=' min _ result);
System.out.println('-10.5的绝对值=' ABS _ result);
System.out.println('4.5的相反数=' negate _ result);
}
4.5 1.5=6.0
4.5-1.5=3.0
4.5*1.5=6.75
4.5/1.5=3
4.5/1.5余数=0.0
4.5和1.5最大数=4.5
4.5和1.5最小数=1.5
-10.5的绝对值=10.5
4.5的相反数=-4.5
这里把除法单独再讲一下,因为除法操作的时候会有除不尽的情况,比如3,5/3,这时会报错java.lang.ArithmeticException:非终止十进制扩展;
没有精确可表示的小数结果。所以这里要考虑除不尽的情况下,保留几位小数,取舍规则。(除法如果可能存在除不进,那就用下面方法)
BigDecimal除法(BigDecimal除数、整数小数位数、整数舍入模式)第一参数表示除数,第二个参数表示小数点后保留位数,第三个参数表示取舍规则。
1、常用方法
ROUND_UP //不管保留数字后面是大是小(0除外)都会进一
ROUND_DOWN //保留设置数字,后面所有直接去除
ROUND_HALF_UP //常用的四舍五入
ROUND_HALF_DOWN //五舍六入
ROUND_CEILING //向正无穷方向舍入
ROUND_FLOOR //向负无穷方向舍入
ROUND_HALF_EVEN //向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,如果保留位数是奇数,使用四舍五入如果是偶数,使用向下舍入
ROUND _不必要的//计算结果是精确的,不需要舍入模式
注意我们最常用的应该是四舍五入(四舍五入)
这里举几个常用的取舍规则
公共静态void main(String[] args) {
BigDecimal a=new BigDecimal(' 1.15 ');
BigDecimal b=new BigDecimal(' 1 ');
//不管保留数字后面是大是小(0除外)都会进一所以这里输出为1.2
BigDecimal divide_1=a.divide(b,1,BigDecimal .ROUND _ UP);
//保留设置数字,后面所有直接去除所以这里输出为1.1
BigDecimal divide_2=a.divide(b,1,BigDecimal .四舍五入);
//常用的四舍五入所以这里输出1.2
BigDecimal divide_3=a.divide(b,1,BigDecimal .ROUND _ HALF _ UP);
//这个可以理解成五舍六入所以这里输出1.1
BigDecimal divide_4=a.divide(b,1,BigDecimal .ROUND _ HALF _ DOWN);
//这里将1.15改成1.16
BigDecimal c=new BigDecimal(' 1.16 ');
//那么这里就符合六入了所以输出变为1.2
BigDecimal divide_5=c.divide(b,1,BigDecimal。ROUND _ HALF _ DOWN);
system . out . println(' divide _ 1=' divide _ 1);
system . out . println(' divide _ 2=' divide _ 2);
system . out . println(' divide _ 3=' divide _ 3);
system . out . println(' divide _ 4=' divide _ 4);
system . out . println(' divide _ 5=' divide _ 5);
}
运行结果
除法_1=1.2
除法_2=1.1
除法_3=1.2
除法_4=1.1
除法_5=1.2
2、取舍规则
因为NumberFormat类的format()方法可以使用BigDecimal对象作为其参数,所以可以使用BigDecimal来格式化货币值、百分比值和超过16位有效数字的通用数值。
以BigDecimal对货币和百分比的格式为例。首先,创建BigDecimal对象,在执行BigDecimal的算术运算后,分别建立对货币和百分比格式的引用,最后使用
作为format()方法的参数,BigDecimal对象输出其格式化的货币值和百分比。
例子
公共静态void main(String[] args) {
//建立货币格式引用
number format currency=number format . getcurrency instance();
//建立百分比格式引用
number format percent=number format . getpercentinstance();
//百分比小数点最多可以有3位数。
percent . setmaximumfractiondigits(3);
//舍入
number format integer instance=number format . getinteger instance();
////金额
BigDecimal loan amount=new BigDecimal(' 188.555 ');
////利率
BigDecimal interest rate=new BigDecimal(' 0.018555555 ');
//如果未指定保留位,则默认保留2位。
system . out . println(' amount:' currency . format(loan amount));
//货币(百分比)格式指定默认的折衷规则是舍入
System.out.println('利率:' percent . format(interest rate));
//舍入有点不一样。188.555四舍五入到189,188.51也是189,但是189.5确实是188,所以不是真的四舍五入。
system . out . println(' rounded:' integer instance . format(贷款金额));
}
运行结果
金额:188.56利率:1.856%: 189。
这里有几点需要说明。
1.如果在格式化过程中没有指定保留数字,默认情况下会保留2个数字。
2.货币(百分比)格式指定默认选择规则是舍入。
3.舍入有点不同。188.555四舍五入到189,188.51也是189,但是189.5确实是188,所以不是真的四舍五入。
以上是讲解java中BigDecimal精度的详细内容。更多关于java的信息,请关注我们的其他相关文章!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。