首页 > 其他分享 >BigDecimal详解

BigDecimal详解

时间:2025-01-09 17:36:04浏览次数:1  
标签:舍入 BigDecimal 舍弃 整数 详解 println ROUND

1、BigDecimal基本介绍

  • 高精度数值计算:BigDecimal是 Java 中用于高精度数值计算的类。它主要用于处理需要精确表示的十进制数,特别是在金融、货币计算等对精度要求极高的领域。双精度浮点型变量double 虽然可以处理16位有效数,但在实际应用中,可能需要对更大或者更小的数进行运算和处理,BigDecimal 就可以用来对超过16位有效位的数进行精确的运算。一般情况下,对于那些不需要准确计算精度的数字,我们可以直接使用Float和Double处理,但是Double.valueOf(String) 和Float.valueOf(String)会丢失精度。所以开发中,如果我们需要精确计算的结果,则必须使用BigDecimal类来操作。
  • 不可变对象:BigDecimal对象是不可变的,这意味着一旦创建,其数值就不能被修改。对BigDecimal对象进行的任何操作(如加法、减法、乘法、除法等)都会返回一个新的BigDecimal对象,而原对象保持不变。这种不可变性有助于确保数据的一致性和线程安全性。

当程序中涉及到金额时,必须使用 BigDecimal 而不是 double 或 float 。

 

1.1、浮点类型坑示例

public static void main(String[] args) {
    float a = 1;
    float b = 0.9f;
    System.out.println(a - b);
}

 

2、BigDecimal 的常用方法

2.1、常用构造方法

  • new BigDecimal(int val):创建一个具有参数所指定整数值的对象。
  • new BigDecimal(double val):(不推荐使用,因为存在精度丢失问题)创建一个具有参数所指定双精度值的对象。
  • new BigDecimal(long val):创建一个具有参数所指定长整数值的对象
  • new BigDecimal(String val):(推荐使用)创建一个具有参数所指定以字符串表示的数值的对象。
public static void main(String[] args) {
    BigDecimal b_int = new BigDecimal(10);
    BigDecimal b_double = new BigDecimal(0.1);
    BigDecimal b_float = new BigDecimal(0.1f);
    BigDecimal b_string = new BigDecimal("0.1");
    BigDecimal b_valueof = BigDecimal.valueOf(0.1);
System.out.println("b_int:" + b_int); System.out.println("b_double:" + b_double); System.out.println("b_float:" + b_float); System.out.println("b_string:" + b_string); System.out.println("b_valueof:" + b_valueof); }

输出如下:

使用构造函数时,推荐用 int 或 String 做参数,如果不满足,则建议使用 BigDecimal.valueOf 方法,该方法可接受 int、long、double、float 做参数,但注意不接受 String。

 

2.2、常用方法

注意:BigDecimal进行运算时必须要保证对象本身不能是null,否则就会抛空指针异常。

 

1)加减乘除

  • add(BigDecimal):加,BigDecimal对象中的值相加,返回BigDecimal对象
  • subtract(BigDecimal):减,BigDecimal对象中的值相减,返回BigDecimal对象
  • multiply(BigDecimal):乘,BigDecimal对象中的值相乘,返回BigDecimal对象
  • divide(BigDecimal):除,BigDecimal对象中的值相除,返回BigDecimal对象。该方法可能会遇到无限精度问题,会抛出异常,使用时需注意。所以我们建议在使用BigDecimal进行除运算时,一定要指定精度和舍入模式。
public static void main(String[] args) {
    BigDecimal a = new BigDecimal("10");
    BigDecimal b = new BigDecimal("20");
    BigDecimal c = new BigDecimal("30");

    BigDecimal add = a.add(b);
    BigDecimal subtract = a.subtract(b);
    BigDecimal multiply = a.multiply(b);
    BigDecimal divide = a.divide(b);

    System.out.println("加结果为:" + add);
    System.out.println("减结果为:" + subtract);
    System.out.println("乘结果为:" + multiply);
    System.out.println("除结果为:" + divide);
// 除不尽将会抛出异常 BigDecimal divide2 = a.divide(c); }

输入结果如下:

 

其他常见方法:

方法 含义
abs() 将BigDecimal对象中的值转换成绝对值
doubleValue() 将BigDecimal对象中的值转换成双精度数
floatValue() 将BigDecimal对象中的值转换成单精度数
longValue() 将BigDecimal对象中的值转换成整数
compareTo(BigDecimal val) 比较大小,返回int类型。0(相等) 1(大于) -1(小于)
toPlainString() 推荐使用,直接转换为字符串且不使用任何计数法
toString() 转换为字符串,但在必要时使用科学计数法。
toEngineeringString() 转换为字符串,但在必要时使用工程计数法。 工程记数法是一种工程计算中经常使用的记录数字的方法,与科学技术法类似,但要求10的幂必须是3的倍数
max(BigDecimal val) 两值比较,返回最大值
negate() 求相反数,正变负,负变正
pow(int n) 求乘方,如BigDecimal.valueOf(2).pow(3)的值为8

 

3、设置精度和舍入模式

BigDecimal 并不代表无限精度,当在两个数除不尽的时候,就会报错。所以我们建议在使用BigDecimal进行除运算时,一定要指定精度和舍入模式。

public static void main(String[] args) {
    BigDecimal b1 = new BigDecimal("1.0");
    BigDecimal b2 = new BigDecimal("3.0");
    // 保留3位小数,且四舍五入
    BigDecimal divide = b1.divide(b2, 3, RoundingMode.HALF_UP);
    System.out.println(divide);//0.33
}

 

3.1、BigDecimal 中的舍入模式

  1. ROUND_UP(向上舍入)
    • 定义与行为:
      • 这种舍入模式总是在非零舍弃部分的左边一位加 1。无论是正数还是负数,只要有需要舍弃的非零部分,就会向上进位。
    • 示例:
      • 对于正数,如将1.1舍入到整数,按照ROUND_UP模式,结果是2。因为小数部分0.1是非零的,所以将整数部分11得到2
      • 对于负数,如将-1.1舍入到整数,结果是-2。因为小数部分0.1是非零的,所以将整数部分-11得到-2
  2. ROUND_DOWN(向下舍入)
    • 定义与行为:
      • 总是舍弃非零舍弃部分,无论正数还是负数,都不进行进位操作。
    • 示例:
      • 对于正数,如将1.9舍入到整数,按照ROUND_DOWN模式,结果是1,因为直接舍弃小数部分0.9
      • 对于负数,如将-1.9舍入到整数,结果是-1。同样是直接舍弃小数部分0.9
  3. ROUND_CEILING(天花板舍入)
    • 定义与行为:
      • 如果是正数,行为类似于ROUND_UP;如果是负数,行为类似于ROUND_DOWN。其目的是将数字舍入到正无穷方向。
    • 示例:
      • 对于正数,如将1.1舍入到整数,结果是2,和ROUND_UP模式相同。
      • 对于负数,如将-1.1舍入到整数,结果是-1,和ROUND_DOWN模式相同。
  4. ROUND_FLOOR(地板舍入)
    • 定义与行为:
      • 如果是正数,行为类似于ROUND_DOWN;如果是负数,行为类似于ROUND_UP。其目的是将数字舍入到负无穷方向。
    • 示例:
      • 对于正数,如将1.9舍入到整数,结果是1,和ROUND_DOWN模式相同。
      • 对于负数,如将-1.9舍入到整数,结果是-2,和ROUND_UP模式相同。
  5. ROUND_HALF_UP(四舍五入)
    • 定义与行为:
      • 如果舍弃部分大于或等于0.5,则在非零舍弃部分的左边一位加1;否则,直接舍弃。这是最常见的舍入模式,符合我们日常的 “四舍五入” 概念。
    • 示例:
      • 1.5舍入到整数,结果是2,因为小数部分0.5满足大于或等于0.5的条件,所以将整数部分11
      • 1.4舍入到整数,结果是1,因为小数部分0.4小于0.5,所以直接舍弃。
  6. ROUND_HALF_DOWN(五舍六入)
    • 定义与行为:
      • 如果舍弃部分大于0.5,则在非零舍弃部分的左边一位加1;否则,直接舍弃。与ROUND_HALF_UP的区别在于,当舍弃部分等于0.5时,不进位。
    • 示例:
      • 1.5舍入到整数,结果是1,因为小数部分等于0.5,不进位。
      • 1.6舍入到整数,结果是2,因为小数部分0.6大于0.5,所以将整数部分11
  7. ROUND_HALF_EVEN(银行家舍入)
    • 定义与行为:
      • 也称为 “银行家舍入”。如果舍弃部分左边的数字是偶数,且舍弃部分等于0.5,则直接舍弃;如果舍弃部分左边的数字是奇数,且舍弃部分等于0.5,则在非零舍弃部分的左边一位加1。对于其他情况,和ROUND_HALF_UP类似。
    • 示例:
      • 2.5舍入到整数,结果是2,因为整数部分2是偶数,且小数部分是0.5,所以直接舍弃。
      • 3.5舍入到整数,结果是4,因为整数部分3是奇数,且小数部分是0.5,所以将整数部分31

 

 

9、最佳实践

public static void main(String[] args) {
    // 使用字符串参数构造函数
    BigDecimal a = new BigDecimal("10");
    // 或使用BigDecimal.valueOf方法
    BigDecimal b = BigDecimal.valueOf(30);

    BigDecimal add = a.add(b);
    BigDecimal subtract = a.subtract(b);
    BigDecimal multiply = a.multiply(b);
    //进行除运算时,指定精度和舍入模式,避免除不尽导致报错
    BigDecimal divide = a.divide(b, 2, RoundingMode.HALF_UP);

    System.out.println("加结果为:" + add);
    System.out.println("减结果为:" + subtract);
    System.out.println("乘结果为:" + multiply);
    System.out.println("除结果为:" + divide);
}

输出如下:

 

标签:舍入,BigDecimal,舍弃,整数,详解,println,ROUND
From: https://www.cnblogs.com/wenxuehai/p/18662563

相关文章

  • C#对Excel打印时,PageSetup 对象详解
    C#对Excel打印时,PageSetup对象详解 PageSetup对象包含所有页面设置的属性(左边距、底部边距、纸张大小等)。下面按“页面”、“页边距”、“页眉/页脚”、“工作表”和“无对应选项卡”五个类别,逐一介绍。一、页面与“页面”选项卡对应的属性有7个。分别为:PrintQuality、Orien......
  • CodeNavi的表达式节点和属性详解
    CodeNavi是一种用于代码检查的规则语言,能够帮助开发者定义复杂的检查规则,以检测代码中的潜在问题和违反编码规范的地方。本文将深入解读CodeNavi的表达式节点和属性,详细介绍其结构和用法。一、表达式节点表达式节点是CodeNavi规则语言中的基本构造块,用于表示代码中的不同元素和......
  • Linux(Centos 7.6)命令详解:tree
    1.命令作用以树状格式列出目录的内容(listcontentsofdirectoriesinatree-likeformat);tree会递归显示子层目录下所有内容,但默认情况下不包括隐藏文件和目录2.命令语法Usage:tree[OPTION]... [<directorylist>]3.参数详解OPTION:-a,all显示所有文件和目录(包......
  • .NET Core:架构、特性和优势详解
    .NETCore:架构、特性和优势详解在软件开发领域,保持领先地位至关重要。随着技术以指数级的速度发展,开发人员不断寻求高效、可扩展且多功能的解决方案来应对现代挑战。.NETCore就是这样一种受到广泛关注的解决方案。在本指南中,我们将深入研究.NETCore的基础知识,探索其架构、功......
  • 分布式锁Redisson详解,Redisson如何解决不可重入,不可重试,超时释放,主从一致问题的分析解
    目录1.Redisson解决不可重入锁导致的死锁问题 2.不可重试问题Pub/Sub的优势锁释放的发布逻辑3.超时释放的问题1.锁的超时释放机制背景2.源码分析2.1锁的获取2.2看门狗机制2.3看门狗续期实现2.4手动设置锁的过期时间总结 4.主从一致性 问题背景......
  • MySQL表锁定问题详解:原因、检测与解决方案
    个人名片......
  • 《深入理解Mybatis原理》MyBatis数据源与连接池详解
    MyBatis数据源DataSource分类MyBatis把数据源DataSource分为三种:UNPOOLED不使用连接池的数据源POOLED使用连接池的数据源JNDI使用JNDI实现的数据源相应地,MyBatis内部分别定义了实现了java.sql.DataSource接口的UnpooledDataSource,PooledDataSource类来表示UNPOOLED、P......
  • Spring 中的 @RestController 注解详解
    @RestController 是SpringMVC中常用的注解,通常用于构建 RESTfulWeb服务。它是 @Controller 和 @ResponseBody 的组合,简化了开发RESTful接口的流程。本文将详细介绍 @RestController 的使用场景、原理以及具体案例。1. @RestController 的作用@RestControl......
  • windows C#-泛型类型参数的约束详解(二)
    未绑定的类型参数没有约束的类型参数(如公共类SampleClass<T>{}中的T)称为未绑定的类型参数。未绑定的类型参数具有以下规则:不能使用!=和==运算符,因为无法保证具体的类型参数能支持这些运算符。可以在它们与System.Object之间来回转换,或将它们显式转换为任何接口......
  • windows C#-泛型类型参数的约束详解(一)
    使用约束的原因约束指定类型参数的功能和预期。声明这些约束意味着你可以使用约束类型的操作和方法调用。如果泛型类或方法对泛型成员使用除简单赋值之外的任何操作,包括调用System.Object不支持的任何方法,则对类型参数应用约束。例如,基类约束告诉编译器,只有此类型的对象......