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. Linux下部署Spring Boot 项目 jar包

    打jar包   在IDEA 2020的最右侧边,选中Maven ,然后双击Lifecycle标签下的package即开始打包,之后就会在target目录下生成jar包. 注意,需要修改pom.xml ...

  2. mysql安全小结

    sql的注入是一个很困扰人的问题,一些恶意攻击者可以利用sql注入来获取甚至是修改数据库中的信息,尤其是一些比较敏感的密码一类的数据. sql注入主要利用mysql 的注释将后续应正常执行的语句注释掉 ...

  3. 「Log」NOIP 2023 游记

    Day 0 打了大半天板子,然后开摆. 打块,快下班的时候玩了猜词游戏. 回家睡大觉. Day 1 早上起床状态良好,收拾收拾就出门了,跟爸妈吃了肯德基,然后坐车到三校区. 才看到 cc0000 之前 ...

  4. K8s新手系列之CronJob

    概述 官方文档:https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/cron-jobs/ CronJob控制器以 Job控制 ...

  5. 【运维必看】雷池社区版自动 SSL:从申请到部署全自动化,让证书续期从此 “无感”!

    雷池社区版自动SSL 作者:夜猫(社区9群) 正常安装雷池,并配置站点,暂时不配置ssl 不使用雷池自带的证书申请. 安装(acme.sh),使用域名验证方式生成证书 先安装gityum instal ...

  6. C#实现语音预处理:降噪、静音检测、自动增益(附Demo源码)

    无论是在音视频录制系统,还是音视频通话系统.或视频会议系统中,对从麦克风采集到的说话的声音数据进行预处理,都是是非常必要的. 语音数据预处理主要包括:​​降噪(Noise Reduction).静音检 ...

  7. DTALK直播预约 | 深度解析大资管行业数字化转型

    在<商业银行理财业务监督管理办法><关于规范金融机构资产管理业务的指导意见>等理财新规.资管新规的要求下,大资管行业结构持续优化,存量金融风险明显收敛.此外,也促使资管行业在产 ...

  8. 八、make编译输出重定向

    4.编译输出重定向 ​ 将 make 命令的标准输出(stdout)和标准错误输出(stderr)重定向到文件,以便于查看编译日志,快速分析定位问题. 1.重定向到同一个文件 语法: make > ...

  9. .NET Core 微服务架构学习与实践系列文章目录

    一.为啥要总结和收集这个系列? 2018年离开了原来的Team加入了新的Team,开始做Java微服务的开发工作,接触了Spring Boot, Spring Cloud等技术栈,对微服务这种架构有了 ...

  10. http流量镜像

    http流量镜像 "流量镜像"是指将网络中的数据流量复制一份,并将这份复制流量发送到另一个目的地(如监控.分析或安全检测系统).这项技术常用于网络安全.故障排查.业务灰度发布等场景 ...