bigdecimal解决精度问题的原理,java bigdecimal比较大小的方法

bigdecimal解决精度问题的原理,java bigdecimal比较大小的方法,详解java中BigDecimal精度问题

本文主要介绍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 . 68686868661

浮点数的值实际上是由特定的数学公式计算出来的。

一、背景

二、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的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: