news 2026/6/3 0:41:37

一算钱领导就让用BigDecimal ,为什么它可以不丢失精度?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
一算钱领导就让用BigDecimal ,为什么它可以不丢失精度?

我们都知道在计算钱的时候首选 BigDecimal,因为它不会导致丢失精度的情况,尤其在金融领域,为了保证数据的精度,往往都会使用BigDecimal。本文就来探讨下为什么BigDecimal可以保证精度不丢失。

类介绍

首先来看一下BigDecimal的类声明以及几个属性:

public class BigDecimal extends Number implements Comparable<BigDecimal> { // 该BigDecimal的未缩放值 private final BigInteger intVal; // 精度,可以理解成小数点后的位数 private final int scale; // BigDecimal中的十进制位数,如果位数未知,则为0(备用信息) private transient int precision; // Used to store the canonical string representation, if computed. // 这个我理解就是存实际的BigDecimal值 private transient String stringCache; // 扩大成long型数值后的值 private final transient long intCompact; }

从例子入手

通过debug来发现源码中的奥秘是了解类运行机制很好的方式。请看下面的testBigDecimal方法:

@Test public void testBigDecimal() { BigDecimal bigDecimal1 = BigDecimal.valueOf(2.36); BigDecimal bigDecimal2 = BigDecimal.valueOf(3.5); BigDecimal resDecimal = bigDecimal1.add(bigDecimal2); System.out.println(resDecimal); }

在执行了BigDecimal.valueOf(2.36)后,查看debug信息可以发现上述提到的几个属性被赋了值:

图片

接下来进到add方法里面,看看它是怎么计算的:

/** * Returns a BigDecimal whose value is (this + augend), * and whose scale is max(this.scale(), augend.scale()). */ public BigDecimal add(BigDecimal augend) { if (this.intCompact != INFLATED) { if ((augend.intCompact != INFLATED)) { return add(this.intCompact, this.scale, augend.intCompact, augend.scale); } else { return add(this.intCompact, this.scale, augend.intVal, augend.scale); } } else { if ((augend.intCompact != INFLATED)) { return add(augend.intCompact, augend.scale, this.intVal, this.scale); } else { return add(this.intVal, this.scale, augend.intVal, augend.scale); } } }

看一下传进来的值:

图片

进入第8行的add方法:

private static BigDecimal add(final long xs, int scale1, final long ys, int scale2) { long sdiff = (long) scale1 - scale2; if (sdiff == 0) { return add(xs, ys, scale1); } else if (sdiff < 0) { int raise = checkScale(xs,-sdiff); long scaledX = longMultiplyPowerTen(xs, raise); if (scaledX != INFLATED) { return add(scaledX, ys, scale2); } else { BigInteger bigsum = bigMultiplyPowerTen(xs,raise).add(ys); return ((xs^ys)>=0) ? // same sign test new BigDecimal(bigsum, INFLATED, scale2, 0) : valueOf(bigsum, scale2, 0); } } else { int raise = checkScale(ys,sdiff); long scaledY = longMultiplyPowerTen(ys, raise); if (scaledY != INFLATED) { return add(xs, scaledY, scale1); } else { BigInteger bigsum = bigMultiplyPowerTen(ys,raise).add(xs); return ((xs^ys)>=0) ? new BigDecimal(bigsum, INFLATED, scale1, 0) : valueOf(bigsum, scale1, 0); } } }

这个例子中,该方法传入的参数分别是:xs=236,scale1=2,ys=35,scale2=1

该方法首先计算scale1 - scale2,根据差值走不同的计算逻辑,这里求出来是1,所以进入到最下面的else代码块(这块是关键):

  • 首先17行校验了一下数值范围

  • 18行将ys扩大了10的n次倍,这里n=raise=1,所以返回的scaledY=350

  • 接着就进入到20行的add方法:

private static BigDecimal add(long xs, long ys, int scale){ long sum = add(xs, ys); if (sum!=INFLATED) return BigDecimal.valueOf(sum, scale); return new BigDecimal(BigInteger.valueOf(xs).add(ys), scale); }

这个方法很简单,就是计算和,然后返回BigDecimal对象:

结论

所以可以得出结论:BigDecimal在计算时,实际会把数值扩大10的n次倍,变成一个long型整数进行计算,整数计算时自然可以实现精度不丢失。同时结合精度scale,实现最终结果的计算。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/31 0:56:37

SpringBoot 实现任意文件在线预览功能

一 文件在线预览在现代工作与生活环境中&#xff0c;文件共享与查看已经成为日常不可或缺的一部分。不过传统的文件处理方式要求用户下载文件到本地后才能查看&#xff0c;这不仅占用了设备的存储空间&#xff0c;还可能导致文件传播效率低下&#xff0c;甚至存在安全隐患。因此…

作者头像 李华
网站建设 2026/5/31 1:47:59

基于CLARK变换和PARK变换的异步电机FOC控制器simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序或模型 4.系统原理简介 4.1 Clark变换&#xff08;三相→两相静止坐标系&#xff09; 4.2 Park变换(两相静止→两相同步旋转坐标系) 4.3 电流环控制 4.4 Park逆变换(d−q→α−β) 4.5 Clark逆变换(α−β→三相) 5.完整工…

作者头像 李华
网站建设 2026/5/31 1:47:58

重组蛋白是什么?从基因到功能蛋白的技术原理解析

在生命科学研究中&#xff0c;蛋白质是执行生物功能的核心分子&#xff0c;而重组蛋白则是科研中最常见、最标准化的蛋白来源之一。所谓重组蛋白&#xff0c;是指通过基因工程手段&#xff0c;将编码目标蛋白的基因导入异源宿主细胞中&#xff0c;由宿主的生物合成体系表达并获…

作者头像 李华
网站建设 2026/5/31 1:47:59

IoT 场景中的 DHCP、ARP、ICMP 到底在干嘛?

&#x1f310; IoT 场景中的 DHCP、ARP、ICMP 到底在干嘛&#xff1f;连上 WiFi ≠ 能通信&#xff0c;真正的网络刚刚开始在 IoT 开发中&#xff0c;你一定见过这些现象&#xff1a; ESP32 显示 WiFi 已连接&#xff0c;但服务器连不上MQTT / HTTP 超时&#xff0c;但 TCP/IP …

作者头像 李华
网站建设 2026/5/31 1:47:58

K8S安装指南与核心操作命令汇总

在云原生时代&#xff0c;Kubernetes&#xff08;简称K8S&#xff09;已成为容器编排的事实标准&#xff0c;无论是企业级应用部署还是个人技术学习&#xff0c;掌握K8S的安装与基础操作都是必备技能。本文将从安装前置准备、具体安装步骤&#xff08;以主流的kubeadm方式为例&…

作者头像 李华