bigdecimal正确用法_深入理解 BigDecimal 的使用

什么是 BigDecimal

BigDecimal 可以表示一个任意大小且精度完全准确的浮点数。

为什么用 BigDecimal 而不用 double

Talk is cheap, Show me the Code.

例 1:

double d1 = 0.3;

double d2 = 0.2;

System.out.println("Double:\t 0,3 - 0,2 = " + (d1 - d2));

float f1 = 0.3f;

float f2 = 0.2f;

System.out.println("Float:\t 0,3 - 0,2 = " + (f1 - f2));

BigDecimal bd1 = new BigDecimal("0.3");

BigDecimal bd2 = new BigDecimal("0.2");

System.out.println("BigDec:\t 0,3 - 0,2 = " + (bd1.subtract(bd2)));

运行结果

Double: 0,3 - 0,2 = 0.09999999999999998

Float: 0,3 - 0,2 = 0.10000001

BigDec: 0,3 - 0,2 = 0.1

从运行结果可以得出,当我们要做精确的小数操作运算时,就需要用到 BigDecimal。那下面做一下除法运算,看看结果:

例 2:

double d1 = 10;

double d2 = 3;

System.out.println("Double:\t 10 / 3 = " + (d1 / d2));

float f1 = 10f;

float f2 = 3f;

System.out.println("Float:\t 10 / 3 = " + (f1 / f2));

// Exception!

BigDecimal bd3 = new BigDecimal("10");

BigDecimal bd4 = new BigDecimal("3");

System.out.println("BigDec:\t 10 / 3 = " + (bd3.divide(bd4)));

运行结果

Double: 10 / 3 = 3.3333333333333335

Float: 10 / 3 = 3.3333333

Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.

当结果除不进,并且没有设置进位的状态值,那就会抛出异常。正确的操作如下:

System.out.println("BigDec:\t 10 / 3 = " + (bd3.divide(bd4,4,BigDecimal.ROUND_HALF_UP)));

运行结果

Double: 10 / 3 = 3.3333333333333335

Float: 10 / 3 = 3.3333333

BigDec: 10 / 3 = 3.3333

总结:当我们在精度要求非常高的时候,需要进行精确的计算,比如:货币,那我们就需要采用 java.math.BigDecimal 类来进行精确计算。

加减乘除

方法

叙述

add(BigDecimal)

BigDecimal对象中的值相加,然后返回这个对象

subtract(BigDecimal)

BigDecimal对象中的值相减,然后返回这个对象

multiply(BigDecimal)

BigDecimal对象中的值相乘,然后返回这个对象

divide(BigDecimal)

BigDecimal对象中的值相除,然后返回这个对象

public class BigDecimalCalculation {

static BigDecimal a = new BigDecimal("0.02");

static BigDecimal b = new BigDecimal("0.03");

public static void main(String[] args) {

System.out.println("a + b = " + a.add(b));

System.out.println("a - b = " + a.subtract(b));

System.out.println("a * b = " + a.multiply(b));

System.out.println("a ÷ b = " + a.divide(b,2,BigDecimal.ROUND_HALF_UP));

}

}

运行结果:

a + b = 0.05

a - b = -0.01

a * b = 0.0006

a ÷ b = 0.67

常用方法

保留两位小数

public class keepTwoDecimal {

public static void main(String[] args) {

BigDecimal num= new BigDecimal(13.154215);

//方式一

DecimalFormat df1 = new DecimalFormat("0.00");

String str = df1.format(num);

System.out.println(str); //13.15

//方式二

// #.00 表示两位小数 #.0000四位小数

DecimalFormat df2 =new DecimalFormat("#.00");

String str2 =df2.format(num);

System.out.println(str2); //13.15

//方式三

//%.2f %. 表示 小数点前任意位数 2 表示两位小数 格式后的结果为f 表示浮点型

String result = String.format("%.2f", num);

System.out.println(result); //13.15

}

}

四舍五入

ROUND_UP

舍入远离零的舍入模式。

在丢弃非零部分之前始终增加数字(始终对非零舍弃部分前面的数字加 1)

例如:2.36 -> 2.4

ROUND_DOWN

接近零的舍入模式。

在丢弃某部分之前始终不增加数字(从不对舍弃部分前面的数字加1,即截短)。

例如:2.36 -> 2.3

ROUND_CEILING

接近正无穷大的舍入模式。

如果 BigDecimal 为正,则舍入行为与 ROUND_UP 相同;

如果为负,则舍入行为与 ROUND_DOWN 相同。

相当于是 ROUND_UP 和 ROUND_DOWN 的合集

ROUND_FLOOR

接近负无穷大的舍入模式。

如果 BigDecimal 为正,则舍入行为与 ROUND_DOWN 相同;

如果为负,则舍入行为与 ROUND_UP 相同。

与 ROUND_CEILING 正好相反

ROUND_HALF_UP

四舍五入

例如:2.35 -> 2.4

ROUND_HALF_DOWN

五舍六入

例如:2.35 -> 2.3

ROUND_HALF_EVEN

如果舍弃部分左边的数字为奇数,则舍入行为与 ROUND_HALF_UP 相同(四舍五入);

如果为偶数,则舍入行为与 ROUND_HALF_DOWN 相同(五舍六入)。

例如:1.15 -> 1.1,1.25 -> 1.2

ROUND_UNNECESSARY

断言请求的操作具有精确的结果,因此不需要舍入。

如果对获得精确结果的操作指定此舍入模式,则抛出 ArithmeticException。

我觉得剩下得了解下就行,而且我感觉剩下有的就是错的,比如 ROUND_HALF_DOWN 和 ROUND_HALF_EVEN,看下面的结果你就知道我说的是为什么了。

public class BigDecimalScaleTest {

public static void main(String[] args) {

double num = 2.35;

BigDecimal b = new BigDecimal(num);

// setScale(1) 表示保留一位小数

System.out.println("ROUND_UP,结果:" + b.setScale(1, BigDecimal.ROUND_UP).doubleValue());

System.out.println("ROUND_DOWN,结果:" + b.setScale(1, BigDecimal.ROUND_DOWN).doubleValue());

System.out.println("ROUND_CEILING,结果:" + b.setScale(1, BigDecimal.ROUND_CEILING).doubleValue());

System.out.println("ROUND_FLOOR,结果:" + b.setScale(1, BigDecimal.ROUND_FLOOR).doubleValue());

System.out.println("ROUND_HALF_UP,结果:" + b.setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue());

System.out.println("ROUND_HALF_DOWN,结果:" + b.setScale(1, BigDecimal.ROUND_HALF_DOWN).doubleValue());

System.out.println("ROUND_HALF_EVEN,结果:" + b.setScale(1, BigDecimal.ROUND_HALF_EVEN).doubleValue());

System.out.println("ROUND_UNNECESSARY,结果:" + b.setScale(1, BigDecimal.ROUND_UNNECESSARY).doubleValue());

}

}

运行结果

ROUND_UP,结果:2.4

ROUND_DOWN,结果:2.3

ROUND_CEILING,结果:2.4

ROUND_FLOOR,结果:2.3

ROUND_HALF_UP,结果:2.4

ROUND_HALF_DOWN,结果:2.4 (来给我解释解释这个,说好的五舍六入呢)

ROUND_HALF_EVEN,结果:2.4 (还有这个)

Disconnected from the target VM, address: '127.0.0.1:59637', transport: 'socket'

Exception in thread "main" java.lang.ArithmeticException: Rounding necessary

小结:常用的就是 ROUND_HALF_UP、ROUND_UP 和 ROUND_DOWN,其它的当个笑话就行

比较

a.compareTo(b)

a > b 返回 1;a = b 返回 0;a < b 返回 -1

public class BigDecimalCompare {

public static void main(String[] args) {

BigDecimal a = new BigDecimal("0.02");

BigDecimal b = new BigDecimal("0.01");

BigDecimal a2 = new BigDecimal("0.02");

System.out.println(" a > b 返回结果:" + a.compareTo(b));

System.out.println(" a = a2 返回结果:" + a.compareTo(a2));

System.out.println(" b < a 返回结果:" + b.compareTo(a));

}

}

运行结果

a > b 返回结果:1

a = a2 返回结果:0

b < a 返回结果:-1

注意事项

在上面的使用中,我们都用的 String 给 BigDecimal 进行 赋值,而没有使用 double 类型赋值,具体的原因看下面的例子:

public class BigDecimalTest {

public static void main(String[] args) {

BigDecimal num1 = new BigDecimal(0.005);

BigDecimal num2 = new BigDecimal(1000000);

BigDecimal num3 = new BigDecimal(-1000000);

//尽量用字符串的形式初始化

BigDecimal num12 = new BigDecimal("0.005");

BigDecimal num22 = new BigDecimal("1000000");

BigDecimal num32 = new BigDecimal("-1000000");

//加法

BigDecimal result1 = num1.add(num2);

BigDecimal result12 = num12.add(num22);

//减法

BigDecimal result2 = num1.subtract(num2);

BigDecimal result22 = num12.subtract(num22);

//乘法

BigDecimal result3 = num1.multiply(num2);

BigDecimal result32 = num12.multiply(num22);

//绝对值

BigDecimal result4 = num3.abs();

BigDecimal result42 = num32.abs();

//除法

BigDecimal result5 = num2.divide(num1,20,BigDecimal.ROUND_HALF_UP);

BigDecimal result52 = num22.divide(num12,20,BigDecimal.ROUND_HALF_UP);

System.out.println("加法用value结果:"+result1);

System.out.println("加法用string结果:"+result12);

System.out.println("减法value结果:"+result2);

System.out.println("减法用string结果:"+result22);

System.out.println("乘法用value结果:"+result3);

System.out.println("乘法用string结果:"+result32);

System.out.println("绝对值用value结果:"+result4);

System.out.println("绝对值用string结果:"+result42);

System.out.println("除法用value结果:"+result5);

System.out.println("除法用string结果:"+result52);

}

}

运行结果:

加法用value结果:1000000.005000000000000000104083408558608425664715468883514404296875

加法用string结果:1000000.005

减法value结果:-999999.994999999999999999895916591441391574335284531116485595703125

减法用string结果:-999999.995

乘法用value结果:5000.000000000000104083408558608425664715468883514404296875000000

乘法用string结果:5000.000

绝对值用value结果:1000000

绝对值用string结果:1000000

除法用value结果:199999999.99999999583666365766

除法用string结果:200000000.00000000000000000000

System.out.println() 中的数字默认是 double 类型的,double 类型的小数计算不准确

使用 BigDecimal 的构造方法传入 double 类型时,计算的结果也是不准确的!

所以我们在使用 BigDecimal 进行赋值的时候,最好使用传入 String 的构造函数,可以确认精度。

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BigDecimal是Java中用于高精度计算的类,它可以处理任意精度的浮点数,并且避免了使用double或float所带来的精度问题。下面是BigDecimal的常见用法: 1. 创建BigDecimal对象 可以使用BigDecimal的构造函数来创建BigDecimal对象,其中可以传入一个字符串表示数字或者一个double类型的值。 例如: ```java BigDecimal bd1 = new BigDecimal("12345678901234567890.123456789"); BigDecimal bd2 = new BigDecimal(1234567890.123456789); ``` 2. 进行基本的算术运算 BigDecimal支持加、减、乘、除等基本的算术运算,可以使用add、subtract、multiply、divide等方法进行计算。 例如: ```java BigDecimal bd1 = new BigDecimal("1.2"); BigDecimal bd2 = new BigDecimal("2.3"); BigDecimal result = bd1.add(bd2); // 加法 result = bd1.subtract(bd2); // 减法 result = bd1.multiply(bd2); // 乘法 result = bd1.divide(bd2); // 除法 ``` 3. 设置精度和舍入模式 可以使用setScale方法设置BigDecimal对象的精度,并且可以设置舍入模式。 例如: ```java BigDecimal bd = new BigDecimal("1.23456789"); bd = bd.setScale(3, RoundingMode.HALF_UP); // 设置精度为3,舍入模式为四舍五入 System.out.println(bd); // 输出结果为1.235 ``` 4. 比较大小 可以使用compareTo方法比较两个BigDecimal对象的大小,返回值为-1、0、1,表示小于、等于、大于。 例如: ```java BigDecimal bd1 = new BigDecimal("1.234"); BigDecimal bd2 = new BigDecimal("1.235"); int result = bd1.compareTo(bd2); // 比较大小 if (result < 0) { System.out.println("bd1 < bd2"); } else if (result == 0) { System.out.println("bd1 = bd2"); } else { System.out.println("bd1 > bd2"); } ``` 5. 转换为其他数据类型 可以使用doubleValue、intValue、longValue等方法将BigDecimal对象转换为其他数据类型。 例如: ```java BigDecimal bd = new BigDecimal("123.456"); double d = bd.doubleValue(); // 转换为double类型 int i = bd.intValue(); // 转换为int类型 long l = bd.longValue(); // 转换为long类型 ``` 以上就是BigDecimal的常见用法,可以根据实际需要进行使用

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值