java.math.BigDecimal使用

在金融、电商等对数值精度要求极高的领域,Java的基本浮点类型(float、double)往往无法满足需求,因为它们会产生精度丢失的问题。而java.math.BigDecimal类提供了完全精确的十进制浮点运算解决浮点精度丢失。

BigDecimal构造

BigDecimal其内部通过BigInteger存储整数部分,再通过scale(小数位数)来确定小数点位置,从而能够表示任意精度的小数。

创建BigDecimal的正确方式是使用字符串构造,避免使用double构造(否则会带入精度误差):

// 推荐方式:通过字符串创建
BigDecimal correct = new BigDecimal("0.1"); // 不推荐:double本身的精度问题会被带入
BigDecimal incorrect = new BigDecimal(0.1); // 实际值可能是0.1000000000000000055...

小数位数(scale)

scaleBigDecimal的核心属性,代表小数部分的位数:

BigDecimal d1 = new BigDecimal("123.45");
BigDecimal d2 = new BigDecimal("123.4500");
BigDecimal d3 = new BigDecimal("12345"); System.out.println(d1.scale()); // 2(两位小数)
System.out.println(d2.scale()); // 4(四位小数)
System.out.println(d3.scale()); // 0(整数)

通过stripTrailingZeros()方法可以移除末尾多余的0,同时自动调整scale:

BigDecimal d = new BigDecimal("123.4500").stripTrailingZeros();
System.out.println(d.scale()); // 2(移除两个0后保留两位小数)

当scale为负数时,表示整数部分末尾有对应数量的0:

BigDecimal d = new BigDecimal("1234500").stripTrailingZeros();
System.out.println(d.scale()); // -2(表示整数1234500末尾有2个0)

精度控制与四舍五入

setScale(int newScale, RoundingMode mode)方法用于调整精度,其中RoundingMode指定舍入规则:

import java.math.RoundingMode;

BigDecimal d = new BigDecimal("123.456789");

// 保留4位小数,四舍五入
BigDecimal rounded = d.setScale(4, RoundingMode.HALF_UP); // 123.4568 // 保留4位小数,直接截断
BigDecimal truncated = d.setScale(4, RoundingMode.DOWN); // 123.4567

常用的RoundingMode包括:

  • HALF_UP:四舍五入(最常用)
  • DOWN:直接截断
  • UP:向上进位
  • HALF_EVEN:银行家舍入法(偶数位四舍五入)

运算规则

BigDecimal的四则运算通过实例方法实现,其中除法需要特别注意精度设置:

BigDecimal a = new BigDecimal("123.456");
BigDecimal b = new BigDecimal("23.456789"); // 加、减、乘运算(精度自动维护)
BigDecimal sum = a.add(b);
BigDecimal diff = a.subtract(b);
BigDecimal product = a.multiply(b); // 除法必须指定精度和舍入模式(否则可能因除不尽报错)
BigDecimal quotient = a.divide(b, 10, RoundingMode.HALF_UP); // 保留10位小数

通过divideAndRemainder()可同时获取商和余数:

BigDecimal n = new BigDecimal("12.345");
BigDecimal m = new BigDecimal("0.12");
BigDecimal[] dr = n.divideAndRemainder(m); System.out.println(dr[0]); // 商:102
System.out.println(dr[1]); // 余数:0.105

比较与相等判断

关键注意点equals()方法不仅比较值,还会比较scale,而compareTo()仅比较数值大小:

BigDecimal d1 = new BigDecimal("123.456");
BigDecimal d2 = new BigDecimal("123.45600"); System.out.println(d1.equals(d2)); // false(scale不同:3 vs 5)
System.out.println(d1.compareTo(d2) == 0); // true(数值相等)

注意:始终使用compareTo()比较两个BigDecimal的值,返回值含义:

  • 0:相等
  • 1:当前对象更大
  • -1:当前对象更小

总结

  • BigDecimal用于表示精确的小数,解决了Java浮点类型的精度丢失问题。
  • 比较BigDecimal的值是否相等,必须使用compareTo()而不能使用equals()。

Java核心类——8.BigDecimal的更多相关文章

  1. 从字节码和JVM的角度解析Java核心类String的不可变特性

    1. 前言 最近看到几个有趣的关于Java核心类String的问题. String类是如何实现其不可变的特性的,设计成不可变的好处在哪里. 为什么不推荐使用+号的方式去形成新的字符串,推荐使用Stri ...

  2. Java核心类

    Java核心类的学习: 常用类库 io流 集合 多线程 网络编程 调试与优化 XML和JSON 枚举.注解和反射 设计模式

  3. Day1 面向对象编程与Java核心类

    this变量 在方法内部,可以使用一个隐含的变量this,它始终指向当前实例.如果没有命名冲突,可以省略this. 但是,如果有局部变量和字段重名,那么局部变量优先级更高,就必须加上this. 构造方 ...

  4. java常用类之BigDecimal

    BigDecimal 小数计算丢失精度问题 在计算机中,所有文件都是以二进制存储的,数字运算也是使用二进制进行计算的,因为计算机中不存在小数点,所以我们通常说的浮点数如float.double都是计算 ...

  5. 【Java常用类】BigDecimal

    BigDecimal 一般的Float类和Double类可以用来做科学计算或工程计算,但在商业计算中, 要求数字精度比较高,故用到java.math.BigDecimal类. BigDecimal类支 ...

  6. Java工具类之——BigDecimal运算封装(包含金额的计算方式)

    日常对于金额计算,应该都是用的BigDecimal,  可是苦于没有好的工具类方法,现在贡献一个我正在用的对于数字计算的工具类,项目中就是用的这个,简单粗暴好用,话不多说,代码奉上(该工具类需要引入g ...

  7. 14-03 java BigInteger类,BigDecimal类,Date类,DateFormat类,Calendar类

    BigInteger类 发 package cn.itcast_01; import java.math.BigInteger; /* * BigInteger:可以让超过Integer范围内的数据进 ...

  8. Java——String类中的compareTo方法总结

    String类的定义:    java.lang  类 String   java.lang.Object      java.lang.String 所有已实现的接口:Serializable, C ...

  9. Java基础学习笔记二十三 Java核心语法之反射

    类加载器 类的加载 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,链接,初始化三步来实现对这个类进行初始化. 加载就是指将class文件读入内存,并为之创建一个Class对象.任 ...

  10. 到头来还是逃不开Java - Java13核心类

    Java13核心类 没有特殊说明,我的所有学习笔记都是从廖老师那里摘抄过来的,侵删 引言 兜兜转转到了大四,学过了C,C++,C#,Java,Python,学一门丢一门,到了最后还是要把Java捡起来 ...

随机推荐

  1. 注解@Transactional事务失效的常见场景

    在<Spring Boot事务管理>中,小编介绍了注解@Transactional的基本属性和使用方法,这里介绍事务失效的八种场景,使大家对注解@Transactional有一个更深刻的认 ...

  2. Spring注解之自定义注解入门

    目录 前言 注解是什么 自定义注解 元注解 @Target @Retention @Documented @Inherited 结束语 Reference 前言   在业务开发过程中,Spring 框 ...

  3. RAG越来越不准?一文详解元数据与标签的系统优化方法(附完整流程图+实用提示词)

    你是不是也遇到过这样的场景? 公司刚花大钱上线AI知识库,结果AI助手总是"答非所问",文档明明都上传了,关键时刻还是找不到想要的答案: 苦心搭了一两个月RAG系统,老板随便一问, ...

  4. SpringBoot的学习

    SpringBoot SpringBoot最核心的东西:自动装配!!! 很重要! 以及他的SpringApplication.run(); 方法 配置用什么写:可以用xml, 和springboot自 ...

  5. SenseVoice部署,并调用api接口

    目录 安装Python 代码下载 虚拟环境 安装依赖 下载模型 修改启用webui.py 启用api.py 安装Python 这个网上找下教程安装下就可以,版本应该没有什么要求,我装的是3.10.7 ...

  6. 简单的php奥运倒计时牌

    1 <?php 2 3 date_default_timezone_set ( "Asia/Shanghai" ); 4 $kaimu = mktime ( 4, 0, 0, ...

  7. C++ set/multiset容器 学习总结

    -------------------------------------set/multiset容器 set/multiset特性 set/multiset的特性是所有元素会根据元素的值自动进行排序 ...

  8. MKL库解线性最小二乘问题(LAPACKE_dgels)

    LAPACK(Linear Algebra PACKage)库,是用Fortran语言编写的线性代数计算库,包含线性方程组求解(AX=B).矩阵分解.矩阵求逆.求矩阵特征值.奇异值等.该库用BLAS库 ...

  9. 利用Python调用outlook自动发送邮件

    ↓↓↓欢迎关注我的公众号,在这里有数据相关技术经验的优质原创文章↓↓↓ 使用Python发送邮件有两种方式,一种是使用smtp调用邮箱的smtp服务器,另一种是直接调用程序直接发送邮件.而在outlo ...

  10. [Compose Multiplatform Desktop] 比官方更好的Compose预览

    前提概要 Compose Multiplatform 是从 Android 的 Jetpack Compose 发展而来的. 所以 Compose 在 Android 上功能最完善,其次是 Deskt ...