你看,ChatGPT都知道优先使用BigDecimal

news2024/12/24 9:00:09

在这里插入图片描述

不是三婶儿偏执,非要吐槽。家人们,咱就是说,按照基操逻辑谁会把严格金额计算相关的数据使用double类型呢…
“我以为吕布已经够勇猛了,这是谁的部下?”

前几天,一同事让帮忙写段代码。内容比较常规,就是按照自定义规则自动计算出一些金额数据。楼主想着暂时也不忙,就帮着写写呗。好家伙!不写不知道,当看到他用Double类型定义存储金额时,内心瞬间沸腾了。嗯,真是个小(大)可(傻)爱(逼)…

在这里插入图片描述

咱就是说,金额相关计算第一考虑肯定是确保精准,优选BigDecimal类型呀,Double类型很容易丢失精度的。尤其是金额,一定要严谨!

你看chatgpt都知道优先使用BigDecimal。

在这里插入图片描述

果不其然,这…真是暴风雨的前奏。我发现有好几个业务模块都使用了这些金额数据做运算,多次加减乘除之类的…

好家伙,“海燕啊,你可长点心吧!”。

在这里插入图片描述

那下面楼主就来详细分析一下,为什么更加建议使用BigDecimal。开整!

文章目录

  • 一、BigDecimal类型数据和Double类型
    • 1.1、BigDecimal
    • 1.2、Double和double的区别
      • 1.2.1、double
      • 1.2.2、Double
      • 1.2.3、double和Double之间的关系
  • 二、两种类型数据的适用场景、优缺点
    • 2.1、Double类型
    • 2.2、BigDecimal类型
  • 三、为什么不建议用Double类型计算金额
    • 3.1、Double类型计算精度易丢失
    • 3.2、数值过大会变为科学记数法形式
  • 四、BigDecimal常用方法
    • 4.1、BigDecimal的初始化
    • 4.2、BigDecimal加法
    • 4.3、BigDecimal减法
    • 4.4、BigDecimal乘法
    • 4.5、BigDecimal除法
    • 4.6、BigDecimal比较大小
    • 4.7、BigDecimal工具类

一、BigDecimal类型数据和Double类型

首先,先来了解一下什么是BigDecimal、什么是Double、什么是double。以及Double和double之间有什么关系。

在这里插入图片描述

1.1、BigDecimal

对于什么是BigDecimal,百度百科中这样描述:

Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数。在实际应用中,需要对更大或者更小的数进行运算和处理。float和double只能用来做科学计算或者是工程计算,在商业计算中要用java.math.BigDecimal。BigDecimal所创建的是对象,我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象。

主要是: 可对超过16位有效位的数进行精确的运算。

1.2、Double和double的区别

1.2.1、double

八大基本数据类型之一,双精度浮点数。

double(双精度浮点型)是计算机使用的一种资料型别。比起单精度浮点数(float),double(双精度浮点数)使用 64 位(8字节) 来储存一个浮点数。 它可以表示十进制的15或16位有效数字,负值取值范围为 -1.7976E+308 到 -4.94065645841246544E-324,正值取值范围为 4.94065645841246544E-324 到 1.797693E+308

1.2.2、Double

Double是基于基本数据类型double的一个封装类,就是我们常用的java.lang.Double。

在这里插入图片描述

1.2.3、double和Double之间的关系

嗯,是有关系,但也不是情侣关系…

在这里插入图片描述

从jdk1.5开始,引入了“自动装箱”、“自动拆箱”的概念,简化了基本数据类型和包装类之间的转化,提高了使用效率。

关于什么是装箱、拆箱。举个栗子:比如我们常用的List就是一个自动装箱、拆箱的体现。

在这里插入图片描述

如图所示,楼主定义了一个Integer类型的list。当往list中放入数据1和2时,会把int类型自动转换为Integer类型,这个过程就是自动装箱。

在这里插入图片描述

反过来说,当从list中取出数据时,会把Integer类型自动转换为int类型,这个过程就是自动拆箱。

自动装箱最大的优点就是:可以直接使用包装类中所有的方法。

我们直接调用即可,方法内部都已经帮我们处理好了。感兴趣的可以看下源码深入了解哈,这里不再过多介绍。
在这里插入图片描述

二、两种类型数据的适用场景、优缺点

2.1、Double类型

适用场景:双精度、非重要性、或“相对模糊”的数据存储。比如:百分比计算。

缺点:数值容易丢失精度。

优点:执行效率高。

2.2、BigDecimal类型

适用场景:较为严谨的数值计算。比如:交易金额相关计算。

优点:数值计算较为精准。

缺点:较Double类型执行效率弱一些。

三、为什么不建议用Double类型计算金额

3.1、Double类型计算精度易丢失

当我们进行数值加减乘除运算时,Double类型很大程度上会产生误差。

如下图示例,楼主定义了2个Double类型数据的加减乘除,运算结果有3个产生了误差。有误差,但是误差不大。

在这里插入图片描述

那么为什么会存在这个问题呢?

可想而知,double类型在运算时,会先将数值转换成二进制然后再做运算。但是在转换过程中,可能会发生存储小数部分的位数不够的现象(无限循环小数),所以很大程度上可能会有非常小的误差产生

因此,不要直接使用入参double类型数值直接进行运算。可考虑使用string类型参数进行处理。

在这里插入图片描述

3.2、数值过大会变为科学记数法形式

当数值过大时,会变为这种科学记数法形式。

在这里插入图片描述
解决方案:可考虑使用BigDecimal类型进行转换。

四、BigDecimal常用方法

4.1、BigDecimal的初始化

楼主分别定义了2个不同类型的入参。

在这里插入图片描述

眼尖的小伙伴估计注意到了,实例化a对象时new BigDecimal(“0.12”)传入的是字符串,实例化b对象时new BigDecimal(0.12)传入的是double数值。大家觉得运行结果会一样吗?

可能不一样吧…嗯,不是可能,是一定!!!

在这里插入图片描述

字符串类型的输出了“0.12”,而double数值类型的却输出了“0.11999999999999999555910790149937383830547332763671875”。

在这里插入图片描述

这又回归到了上面说所的二进制转换存储小数部分的位数不够,造成的误差。使用double类型初始化BigDecimal对象,进行运算时可能会出现精度不准确的问题。

在这里插入图片描述

所以一定注意:不要使用double类型作为入参,直接去new一个BigDecimal对象!可能会有精度误差!

那么,为什么string就可以呢?

string是不可变的,定义为string之后再转换为数值肯定是固定的啊。

底层很多实现也是这个原理。比如BigDecimal.valueOf()方法,如果输入的是double类型,实质上源码中还是先转化为了字符串。

在这里插入图片描述

对于整型或保留小数位的,也有相应的处理方法。

在这里插入图片描述

方法有很多,大家想了解的可自行研究下,楼主就不再一一示例啦。

在这里插入图片描述

4.2、BigDecimal加法

BigDecimal add(BigDecimal augend)

在这里插入图片描述

两个BigDecimal类型数据相加,方法调用、及运行效果。

在这里插入图片描述

4.3、BigDecimal减法

BigDecimal subtract(BigDecimal subtrahend)

在这里插入图片描述
两个BigDecimal类型数据相减,方法调用、及运行效果。

在这里插入图片描述

4.4、BigDecimal乘法

BigDecimal multiply(BigDecimal multiplicand)

在这里插入图片描述

两个BigDecimal类型数据相乘,方法调用、及运行效果。

在这里插入图片描述

4.5、BigDecimal除法

BigDecimal divide(BigDecimal divisor)

在这里插入图片描述

两个BigDecimal类型数据相除,方法调用、及运行效果。

在这里插入图片描述

哎呦,惊喜不惊喜,意外不意外?相除的时候出现了无限循环小数

因此 相除的场景下尽可能设置保留小数位,可避免运算当中抛出异常

在这里插入图片描述

4.6、BigDecimal比较大小

楼主分别定义了2个值为“0.12”的数据a、b,以及值为“0.120”的数据c进行比较。

在这里插入图片描述

可以发现:相同值“0.12”通过双等号对比返回的结果是false,equals对比返回的是true。而“0.12”和“0.120”实质上数值大小是一样的,但通过双等号或equals进行对比,返回均为false

那么,对于BigDecimal类型如何比较大小呢?(叫我靓妹我就告诉你…)

在这里插入图片描述

方法就是:使用compareTo方法进行比较

在这里插入图片描述

a、b两值进行比较:a.compareTo(b) 。 结果为0表示a、b值相等。结果为-1表示a小于b。结果为1表示a大于b

4.7、BigDecimal工具类

为大家附上常用的操作工具类,直接调用即可。


package com.wss.demo.cas;

import java.math.BigDecimal;

public class ArithUtil {


    private static final int DEF_DIV_SCALE = 2; // 小数点后的保留位数

    /**
     * Double精确的加法运算
     *
     * @param d1 被加数
     * @param d2 加数
     * @return 两个参数的和
     */
    public static BigDecimal add(double d1, double d2) {
        BigDecimal value1 = new BigDecimal(Double.toString(d1));
        BigDecimal value2 = new BigDecimal(Double.toString(d2));
        return value1.add(value2);
    }

    /**
     * Double精确的减法运算
     *
     * @param d1 被减数
     * @param d2 减数
     * @return 两个参数的差
     */
    public static BigDecimal sub(double d1, double d2) {
        BigDecimal value1 = new BigDecimal(Double.toString(d1));
        BigDecimal value2 = new BigDecimal(Double.toString(d2));
        return value1.subtract(value2);
    }

    /**
     * Double精确的乘法运算
     *
     * @param d1 被乘数
     * @param d2 乘数
     * @return 两个参数的积
     */
    public static BigDecimal mul(double d1, double d2) {
        BigDecimal value1 = new BigDecimal(Double.toString(d1));
        BigDecimal value2 = new BigDecimal(Double.toString(d2));
        return value1.multiply(value2);
    }

    /**
     * Double精确的除法运算, 当出现除不尽的情况时, 精确到小数点以后n位, 以后的数字四舍五入
     *
     * @param d1 被除数
     * @param d2 除数
     * @return 两个参数的商
     */
    public static BigDecimal div(double d1, double d2) {
        return div(d1, d2, DEF_DIV_SCALE);
    }

    /**
     * Double精确的除法运算, 当出现除不尽的情况时, 精确到小数点以后n位, 以后的数字四舍五入
     *
     * @param d1    被除数
     * @param d2    除数
     * @param scale 表示需要精确到小数点的后几位
     * @return 两个参数的商
     */
    public static BigDecimal div(double d1, double d2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("参数[scale]必须是正整数或者零");
        }
        BigDecimal value1 = new BigDecimal(Double.toString(d1));
        BigDecimal value2 = new BigDecimal(Double.toString(d2));
        return value1.divide(value2, scale, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 比较大小
     */
    public static boolean equalTo(BigDecimal b1, BigDecimal b2) {
        if(b1 == null || b2 == null) {
            return false;
        }
        return 0 == b1.compareTo(b2);
    }

}

嗯,今天的总结就先到这吧。散会了,别忘记给三婶儿点个赞哈~

在这里插入图片描述

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

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

相关文章

iTerm2 的配置与美化

前言 iTerm2是默认终端的替代品&#xff0c;也是目前Mac系统下最好用的终端工具&#xff0c;集颜值和效率于一身。 最近换了一台新的 MacBook Pro &#xff0c;需要重装电脑上的常用软件。为了将 ITerm2 DIY为自己喜欢的样子&#xff0c;花了不少时间。为了方便下次再配置&…

python五子棋代码最简单的,python五子棋代码画棋盘

大家好&#xff0c;本文将围绕python五子棋代码输赢逻辑判断展开说明&#xff0c;如何用python制作五子棋游戏是一个很多人都想弄明白的事情&#xff0c;想搞清楚python五子棋代码最简单的需要先了解以下几个事情。 1、求解用python 编写五子棋怎样编写判断输赢的函数&#xff…

C++项目——高并发内存池(1)--介绍及定长内存池

1.什么是内存池 1.1 池化技术 将程序中需要经常使用的核心资源先申请出来&#xff0c;放在一个池内&#xff0c;由程序自己管理&#xff0c;这样可以提高资源的使用效率&#xff0c;也可以保证本程序占有的资源数量。 比如之前博文实现的线程池&#xff0c;就是预先的申请出…

CRM哪家好?这5个CRM管理系统很好用!

CRM哪家好&#xff1f;这5个CRM管理系统很好用&#xff01; CRM(Customer Relationship Management)即客户关系管理&#xff0c;能够帮助提高客户的价值、满意度、赢利性和忠实度&#xff0c;缩减销售周期和销售成本、增加收入、寻找扩展业务所需的新的市场和渠道&#xff0c;…

浅谈c++引用

浅谈c 在这里开设 <<浅谈C>> 系列专题,针对C重点内容展开探讨与观察底层,同时也是一个面试专栏,所选知识大多为面试常见问题.前期较为基础,难度会逐渐上升哦~ 本专栏采用经典的哲学三段论编写:是什么|为什么|怎么做 力图精简,高效. 第一章: 浅谈C函数重载 传送门…

ansible剧本(playbook)

目录 一、playbooks 概述以及实例操作 1、playbooks 的组成 2、操作示例一&#xff1a; 2.1 编写yaml文件也就是playbook 2.2 修改配置文件并放入/opt/目录下 2.3 运行playbook 3、操作实例二&#xff1a;定义、引用变量 4、操作示例三&#xff1a;指定远程主机sudo切换…

音频格式、参数、开发相关总结

常见的语音格式介绍PCM&#xff1a;音频纯裸数据。WAV&#xff1a;微软在windows存储的一种纯裸数据格式。AIFF&#xff1a;苹果在Mac上存储的一种纯裸数据格式。MP3&#xff1a;为ISO/IEC国际标准&#xff0c;是现在最普及的一种数字音频编码和有损压缩格式&#xff0c;几乎所…

Android Spider XX兔 Wechat Cookie 校验 注册案例(二)

声明 此次案例只为学习交流使用&#xff0c;抓包内容、敏感网址、数据接口均已做脱敏处理&#xff0c;切勿用于其他非法用途&#xff1b; 文章目录声明前言一、资源推荐二、任务说明三、App抓包分析四、还原JS加密1、Date类2、MD5类3、组合调用还原 api_token 参数4、execjs模…

04- 图像卷积及图片的模糊和边缘检测 (OpenCV基础) (机器视觉)

知识重点 padding指的就是填充的0的圈数重构图片大小: img cv2.resize(img, dsize(300, 300))模糊操作: dst cv2.filter2D(img, -1, kernel) kernel np.ones((5, 5), np.float32)/ 25 dst cv2.filter2D(img, -1, kernel) # 卷积操作 模糊操作: 方盒滤波: dst cv2.b…

AD使用教程 图文并茂 AD2020四层板

文章目录设计流程图&#xff1a;资源下载&#xff1a;自定义快捷键&#xff1a;&#xff08;按照个人习惯&#xff09;默认快捷键&#xff1a;一、软件主页面1.主界面2.Panels面板3.系统设置3.自定义快捷键4.新建工程二、原理图库1.原理图库面板2.管脚属性三、原理图绘制绘制步…

C++011-C++循环+枚举

文章目录C011-C循环枚举枚举枚举思想枚举举例题目描述 统计因数题目描述 质数判定错误方法一&#xff1a;优化方法1&#xff1a; 用break实现优化优化方法2&#xff1a; sqrt(n)题目描述 水仙花数题目描述 7744问题实现方法1优化方法2题目描述 余数相同问题题目描述 特殊自然数…

《第一行代码》 第六章:数据库与存储方案

一&#xff0c;持久化技术简介 也就是数据存储在内存中&#xff0c;会丢失。需要存储在存储设备中。而持久化技术&#xff0c;就是提供了手段&#xff0c;让数据再试瞬时状态和持久状态之间转换。 安卓开发提供了三种数据的持久化技术&#xff1a; 二&#xff0c;文件存储 …

【HDFS】FsDatasetImpl#getReplicaVisibleLength

调用点 DataNode.getReplicaVisibleLength(ExtendedBlock) (org.apache.hadoop.hdfs.server.datanode) // ClientDataNodeProtocolBlockChecksumComputer in BlockChecksumHelper.BlockChecksumComputer(DataNode, ExtendedBlock, BlockChecksumOptions) (org.apache.hadoop.hd…

ros中时间的概念:ros::Time、ros::Duration、定时器ros::Timerros::Rate、ros::WallTime

1. ros时间格式说明 有时刻和持续时长(可以是负数)&#xff0c;分为秒和纳秒&#xff0c;换算关系&#xff1a;1sec1e9nsec。Time指的是某个时刻&#xff0c;而Duration指的是某个时段。 int32 sec int32 nsec 2. ros::Time::now() 记录当前时刻 3. ros::Duration 代表持续的…

Linux 输出重定向 “>”、“>>”、“freopen”

有时候&#xff0c;我们编码时会使用printf或fprintf去打印输出调试信息或者报错信息&#xff0c;但正常这样去打印&#xff0c;只会显示在终端&#xff0c;如果终端关闭了&#xff0c;或者系统宕机了等&#xff0c;这些输出信息就没有了&#xff0c;为了将这些重要的信息保存下…

java诊断与调优常用命令jmap、jstack、jstat使用实战

java应用运行过程中难免会出现问题&#xff0c;特别是在生产环境&#xff0c;发生异常或宕机情况&#xff0c;需要诊断与分析&#xff0c;定位原因&#xff0c;进行优化&#xff0c;避免下次再次出现问题。 虽然现在有很多可视化工具&#xff0c;使用起来比命令行更方便&#x…

开学季好用电容笔有哪些?好用实惠的电容笔推荐

随着科学技术的快速发展&#xff0c;ipad的影响力越来越大&#xff0c;而且ipad的用户也越来越多&#xff0c;如果要提高ipad的功能&#xff0c;让ipad更加有趣&#xff0c;那么就需要一款非常适合自己&#xff0c;并且非常实用的电容笔。那么&#xff0c;究竟该选择哪个品牌的…

SpringBoot整合分布式锁redisson

1、导入maven坐标<!-- 用redisson作为所有分布式锁&#xff0c;分布式对象等功能框架--><dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.12.5</version></dependency>2、red…

蓝牙 - BLE中的连接和扫描参数设定

连接参数 / Connection Parameters 连接参数由发起设备与连接请求一起发送&#xff0c;当连接建立后&#xff0c;任何一个设备都可以修改。这些参数如下&#xff1a; 连接间隔 / Connection Interval 在低功耗蓝牙连接中&#xff0c;使用了跳频方案。两台设备发送各自数据和接…

day48【代码随想录】动态规划之最长递增子序列、最长连续递增序列、最长重复子数组

文章目录前言一、最长递增子序列&#xff08;力扣300&#xff09;二、最长连续递增序列&#xff08;力扣674&#xff09;三、最长重复子数组&#xff08;力扣718&#xff09;前言 1、最长递增子序列 2、最长连续递增序列 3、最长重复子数组 一、最长递增子序列&#xff08;力扣…