分享BigDecimal金额计算的4种方式

news2024/10/5 15:33:47

基本介绍

金额计算这块通常都是基于2位小数的四舍五入,如果是自己的系统内部功能金额位数一般都是固定的,在正常的加减乘除运算逻辑都是保留同样位数的,但是乘法和除法相对比较特殊,在计算小数的部分可能会计算出更多位数的小数点,如若需要将计算后的金额数据与某个值进行对比时,就需要考虑数据部分的完全相等了,在应对此种情况的数据逻辑时常见的有两种,第一种是两个数值相见,取绝对值的误差阈值,若在允许的阈值范围内(比如两个数值都是最多2位小数,阈值设置为0.0001),则认为它们是相等的;第二种则是需要知晓该金额在计算过程中所使用的计算方式,采用统一的计算方式计算得出同样的结果即可。

去年实现的一个功能中正好就使用到了多种小数位数的计算方式,大概是4种:四舍五入、截位法、四舍六入五成双、正舍负入(实际还有更多种),这些数据的计算都可以有相关的代码计算方式得出,本次主要分享Math和BigDecimal,参考如下:

Math

@RunWith(JUnit4.class)
public class CalculateMathTest {

    /**
     * 保留2位小数,四舍五入
     */
    @Test
    public void round() {
        System.out.println(Math.round(12345.554 * 100) / 100D);
        System.out.println(Math.round(12345.555 * 100) / 100D);
        System.out.println(Math.round(12345.556 * 100) / 100D);
    }

    /**
     * 保留2位小数,正舍负入(ceil:反过来,正入负舍)
     */
    @Test
    public void floor() {
        System.out.println(Math.floor(123.554 * 100) / 100D);
        System.out.println(Math.floor(123.555 * 100) / 100D);
        System.out.println(Math.floor(123.556 * 100) / 100D);

        System.out.println(Math.floor(-123.554 * 100) / 100D);
        System.out.println(Math.floor(-123.555 * 100) / 100D);
        System.out.println(Math.floor(-123.556 * 100) / 100D);
    }

}

尝试着写了点小demo,发现Math这个数学函数类提供的API重点并不在于金额的计算上,所以找到的金额计算API比较少,在金额计算这块比较鸡肋(先乘以100再除以100得到带小数位数的金额),也算是满足了本次4种金额计算方式中的两种了。

BigDecimal

/**
 * 保留2位小数,四舍五入
 */
@Test
public void round() {
    System.out.println(new BigDecimal("12345.554").setScale(2, BigDecimal.ROUND_HALF_UP));
    System.out.println(new BigDecimal("12345.555").setScale(2, BigDecimal.ROUND_HALF_UP));
    System.out.println(new BigDecimal("12345.556").setScale(2, BigDecimal.ROUND_HALF_UP));
}
/**
 * 保留2位小数,正舍负入
 */
@Test
public void floor() {
    System.out.println(new BigDecimal("12345.554").setScale(2, BigDecimal.ROUND_FLOOR));
    System.out.println(new BigDecimal("12345.555").setScale(2, BigDecimal.ROUND_FLOOR));
    System.out.println(new BigDecimal("12345.556").setScale(2, BigDecimal.ROUND_FLOOR));
    System.out.println();
    System.out.println(new BigDecimal("-12345.554").setScale(2, BigDecimal.ROUND_FLOOR));
    System.out.println(new BigDecimal("-12345.555").setScale(2, BigDecimal.ROUND_FLOOR));
    System.out.println(new BigDecimal("-12345.556").setScale(2, BigDecimal.ROUND_FLOOR));
}
/**
 * 保留2位小数,截位法
 */
@Test
public void down() {
    System.out.println(new BigDecimal("12345.554").setScale(2, BigDecimal.ROUND_DOWN));
    System.out.println(new BigDecimal("12345.555").setScale(2, BigDecimal.ROUND_DOWN));
    System.out.println(new BigDecimal("12345.556").setScale(2, BigDecimal.ROUND_DOWN));
}
/**
 * 保留2位小数,四舍六入五成双
 */
@Test
public void even() {
    System.out.println(new BigDecimal("12345.234").setScale(2, BigDecimal.ROUND_HALF_EVEN));
    System.out.println(new BigDecimal("12345.236").setScale(2, BigDecimal.ROUND_HALF_EVEN));
    System.out.println(new BigDecimal("12345.235").setScale(2, BigDecimal.ROUND_HALF_EVEN));
    System.out.println(new BigDecimal("12345.245").setScale(2, BigDecimal.ROUND_HALF_EVEN));
    System.out.println();
    System.out.println(new BigDecimal("12345.2450").setScale(2, BigDecimal.ROUND_HALF_EVEN));
    System.out.println(new BigDecimal("12345.2451").setScale(2, BigDecimal.ROUND_HALF_EVEN));
    System.out.println(new BigDecimal("12345.2452").setScale(2, BigDecimal.ROUND_HALF_EVEN));
    System.out.println(new BigDecimal("12345.2453").setScale(2, BigDecimal.ROUND_HALF_EVEN));
    System.out.println(new BigDecimal("12345.2454").setScale(2, BigDecimal.ROUND_HALF_EVEN));
    System.out.println(new BigDecimal("12345.2455").setScale(2, BigDecimal.ROUND_HALF_EVEN));
    System.out.println(new BigDecimal("12345.2456").setScale(2, BigDecimal.ROUND_HALF_EVEN));
    System.out.println(new BigDecimal("12345.2457").setScale(2, BigDecimal.ROUND_HALF_EVEN));
    System.out.println(new BigDecimal("12345.2458").setScale(2, BigDecimal.ROUND_HALF_EVEN));
    System.out.println(new BigDecimal("12345.2459").setScale(2, BigDecimal.ROUND_HALF_EVEN));
}

其它说明

BigDecimal中提供了多种金额计算的方法,在RoundingMode类中也单独声明(封装)了一些运算规则的实现,四舍六入五成双又称银行间算法,如果跨界了还是不太容易理解的,本次实践呢又拿出来了多个示例输出来理解,所以我整理的知识点为:

(1)保留两位小数,所以至少应该精确到3位小数,根据第三位小数的值来判断如何第2位小数位来进位;

(2)小数点第3位如果是4则舍去,如果是6则进1;

(3)小数点第3位如果是5,且无第4位小数,则观察第2位小数,若为基数则进1,若为偶数则舍去;

(4)小数点第3位如果是5,且存在第4位小数,则观察第4位小数,若为0则舍去,否则则进1;

所以,这里的四舍六入五成双的输出结果为:

分享BigDecimal金额计算的4种方式欢迎来到陈冬冬的个人经验分享平台https://www.chendd.cn/blog/article/1649745859662635010.html 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/449668.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【微服务】搭建Consul集群服务和Consul配置中心

文章目录 一、传统配置文件的弊端二、微服务配置中心三、主流的配置中心四、Consul 配置操作1.添加配置信息2.获取配置信息 五、单点服务器Consul集群 一、传统配置文件的弊端 静态化配置,例如env文件配置文件无法区分环境配置文件过于分散历史版本无法查看 配置中…

5.5、线程池同步机制类封装及线程池实现

代码地址 5.5、线程池同步机制类封装及线程池实现 1.线程池2.代码实现①锁Ⅰ、locker.hⅡ、locker.cpp ②条件变量Ⅰ、cond.hⅡ、cond.cpp ③信号量Ⅰ、sem.hⅡ、sem.cpp ④线程池Ⅰ、threadpool.hⅡ、threadpool.cpp 1.线程池 线程池是由服务器预先创建的一组子线程&#xf…

行为识别预警系统 opencv

行为识别预警系统通过pythonopencv网络模型技术,行为识别预警系统对现场画面中人的行为进行智能分析,发现违规行为自动抓拍告警,同步回传后台存档提醒值班人员及时处理。OpenCV的全称是Open Source Computer Vision Library,是一个…

CVE漏洞复现-CVE-2019-5736 Docker逃逸

CVE-2019-5736 Docker逃逸 Docker是什么? Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux或Windows操作系统的机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有…

JAVA实现AES加密、解密附代码

大家好,今天我们一起来学习 Java中的加密解密技术, java是一门面向对象的语言,使用它的开发人员都是非常聪明的人,他们对数据的安全性要求很高。在实际的应用中,我们都需要对数据进行加密、解密处理,这在 j…

【数据结构】第十三站:排序(上)

本文目录 一、排序概念二、插入排序1.插入排序的基本思想2.算法实现3.时间复杂度分析 三、希尔排序1. 希尔排序的思想2.希尔排序的代码实现3.希尔排序和插入排序的性能测试比较4.希尔排序的时间复杂度 四、直接选择排序1.基本思想2.直接选择排序的步骤3.直接选择排序的代码实现…

接口自动化测试用例如何设计?

说到自动化测试,或者说接口自动化测试,多数人的第一反应是该用什么工具,比如:Python Requests、Java HttpClient、Apifox、MeterSphere、自研的自动化平台等。大家似乎更关注的是哪个工具更优秀,甚至出现“ 做平台的 &…

音视频开发开发核心知识+小白入门必看基础知识

音视频开发是一个广泛的领域,它涉及到多个技术领域,包括音频编解码、视频编解码、媒体容器格式、流媒体传输、音视频处理等。以下是音视频开发的一些基础知识: 音频编解码器:音频编解码器是将数字音频信号编码成一种压缩格式&…

什么原因会导致香港轻量云服务器运行缓慢?

对于外贸企业主来说,想要为自己的网站选择一个可靠的主机供应商,并考虑使用香港轻量云服务器,则本文是必读的。本文将探讨租用香港轻量云服务器后遇到的运行缓慢的问题。下文这些因素被视为其中的主要因素。仔细分析它们中的每一个将帮助您确…

华为OD机试真题(Java),5键键盘的输出(100%通过+复盘思路)

一、题目描述 有一个特殊的5键键盘,上面有a,ctrl-c,ctrl-x,ctrl-v,ctrl-a五个键。 a键在屏幕上输出一个字母a;ctrl-c将当前选择的字母复制到剪贴板;ctrl-x将当前选择的字母复制到剪贴板&#…

python 打包新方案

首先是打包一个最简单的python 代码使用 pyinstaller import os #直接读取文件获得python.exe 路径 # 待执行python路径 with open("path_run.txt","r",encoding"utf-8") as f:python_exe,pyf.readlines() os.system("{} {}".format(p…

关于Acunetix(AWVS)激活时候失败可能的方法

关于Acunetix(AWVS)激活的时候失败,可能的解决方法 如果自己的激活包大概率没有问题,但是自己却激活不了 可以在服务中关闭所有的进程,再进行文件替换 方法如下: 1.先卸载文件,卸载的干干净净 2.正常安装 3.安装完毕…

cuDNN 的初始设计

cuDNN V1.0在2014年的发布,并集成到 Caffe、Paddle 等深度学习框架中。论文 cuDNN: Efficient Primitives for Deep Learning 介绍了 NVIDIA 对于该库的设计和实现。近十年间,NVIDIA 迭代推出了8代架构,cuDNN 也更新到 8.9。硬件上引入了 Tensor Core&am…

超级详细的 VirtualBox 虚拟机安装 及入门教程

一、前言 虚拟机(Virtual Machine)指通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的完整计算机系统。在实体计算机中能够完成的工作在虚拟机中都能够实现。 虚拟机是在一些开发测试工作中常常需要用到的功能,常见的虚拟机…

数学建模算法汇总(全网最全!含matlab案例代码)

数学建模常用的算法分类 全国大学生数学建模竞赛中,常见的算法模型有以下30种: 最小二乘法数值分析方法图论算法线性规划整数规划动态规划贪心算法分支定界法蒙特卡洛方法随机游走算法遗传算法粒子群算法神经网络算法人工智能算法模糊数学时间序列分析马…

【对比度增强】Learning Tone Curves for Local Image Enhancement(LTMNet)

文章目录 0. 前言1. 理解1.1 整体框架1.2 网络结构1.3 细节 2. 亮点3. 总结 0. 前言 LTMNet这篇文章借鉴了CLAHE算法,所有步骤与CLAHE一致,不同之处在于LTMNet中局部映射曲线是通过CNN预测得到,而CLAHE中是通过直方图均衡化而得。关于CLAHE&…

MySQL_第10章_创建和管理表

第10章_创建和管理表 讲师:尚硅谷 - 宋红康(江湖人称:康师傅) 官网: http://www.atguigu.com 1. 基础知识 1.1 一条数据存储的过程 存储数据是处理数据的第一步 。只有正确地把数据存储起来,我们才能…

【C++11】智能指针

目录 一、异常层层嵌套执行流乱跳容易导致内存泄漏 二、使用智能指针解决上述问题 1、RAII 2、像指针一样 3、智能指针RAII运算符重载 三、C98的auto_ptr 四、C11的unique_ptr和shared_ptr 1、unique_ptr唯一指针 2、shared_ptr共享指针 2.1shared_ptr是否线程安全 …

MySQL_第09章_子查询

第09章_子查询 讲师:尚硅谷 - 宋红康(江湖人称:康师傅) 官网: http://www.atguigu.com 子查询指一个查询语句嵌套在另一个查询语句内部的查询,这个特性从 MySQL 4.1 开始引入。 SQL 中子查询的使用大大…

计算机组成原理 作业5

作业5 题量: 21 满分: 100 作答时间:03-23 09:45至03-29 23:59 91.7分 一. 单选题(共11题,35分) 1. (单选题, 3分)计算机的存储器采用分级存储体系的主要目的是________。 A. 便于读写数据B. 便于系统…