详解BigDecimal

news2024/9/17 7:27:03

目录

1.概述

2.基本API

2.1.创建 BigDecimal 对象:

2.3.基本运算方法:

2.4.精度控制方法:

2.5.比较

2.6.转换

3.注意事项

4.底层实现原理


1.概述

精度丢失,由于现代计算机中采用了浮点数来表示小数,这种表示法会存在精度丢失的问题。想要了解精度丢失的原因,可以去看博主另一篇文章,里面详细解释了其中的原因:

详解浮点数__BugMan的博客-CSDN博客

下面举一个精度丢失的例子:

// 商品价格
double price1 = 19.99;
double price2 = 9.99;
double price3 = 4.99;

// 商品数量
int quantity1 = 2;
int quantity2 = 3;
int quantity3 = 1;

// 计算每种商品的小计
double subtotal1 = price1 * quantity1;
double subtotal2 = price2 * quantity2;
double subtotal3 = price3 * quantity3;

// 计算总价
double total = subtotal1 + subtotal2 + subtotal3;

// 输出结果
System.out.println("商品1小计:" + subtotal1);
System.out.println("商品2小计:" + subtotal2);
System.out.println("商品3小计:" + subtotal3);
System.out.println("购物车总价:" + total);

摸出手机算一下就知道,本来总价应该等于74.94,但是实际的运行结果等于: 

这种精度丢失在诸如金融、航天等需要高精度运算的场景下是无法接受的,为了保证精度,JDK中推出了BigDecimal类型,用来进行浮点数的精确计算。将上面的例子改为BigDecimal后:

// 商品价格
BigDecimal price1 = new BigDecimal("19.99");
BigDecimal price2 = new BigDecimal("9.99");
BigDecimal price3 = new BigDecimal("4.99");
        
// 商品数量
int quantity1 = 2;
int quantity2 = 3;
int quantity3 = 1;
        
// 计算每种商品的小计
BigDecimal subtotal1 = price1.multiply(new BigDecimal(quantity1));
BigDecimal subtotal2 = price2.multiply(new BigDecimal(quantity2));
BigDecimal subtotal3 = price3.multiply(new BigDecimal(quantity3));
        
// 计算总价
BigDecimal total = subtotal1.add(subtotal2).add(subtotal3);
        
// 输出结果
System.out.println("商品1小计:" + subtotal1);
System.out.println("商品2小计:" + subtotal2);
System.out.println("商品3小计:" + subtotal3);
System.out.println("购物车总价:" + total);

结果:

2.基本API

2.1.创建 BigDecimal 对象:

  • BigDecimal(String val):使用字符串表示创建一个 BigDecimal对象。

  • BigDecimal(double val):使用双精度浮点数创建一个 BigDecimal对象。

  • BigDecimal(BigInteger val):使用 BigInteger对象创建一个BigDecimal 对象。

BigDecimal bigDecimal1=new BigDecimal("0.8");
BigDecimal bigDecimal2=new BigDecimal(0.8);
BigDecimal bigDecimal3=new BigDecimal(8);

2.3.基本运算方法:

  • add(BigDecimal augend):加法操作,将当前 BigDecimal 对象与参数相加。

  • subtract(BigDecimal subtrahend):减法操作,将当前 BigDecimal 对象减去参数。

  • multiply(BigDecimal multiplicand):乘法操作,将当前 BigDecimal 对象与参数相乘。

  • divide(BigDecimal divisor):除法操作,将当前 BigDecimal 对象除以参数。

  • pow(int exponent):指数操作,将当前 BigDecimal 对象的幂次方计算。

BigDecimal bigDecimal1=new BigDecimal("0.8");
BigDecimal bigDecimal2=new BigDecimal("0.2");
System.out.println(bigDecimal1.add(bigDecimal2));
System.out.println(bigDecimal1.multiply(bigDecimal2));
System.out.println(bigDecimal1.divide(bigDecimal2));
System.out.println(bigDecimal1.pow(2));

2.4.精度控制方法:

  • setScale(int newScale):设置 BigDecimal对象的精度(小数点后的位数)。

  • setScale(int newScale, RoundingMode roundingMode):设置 BigDecimal 对象的精度,并指定舍入模式。

  • round(MathContext mc):使用指定的舍入规则舍入当前 BigDecimal对象。

BigDecimal number = new BigDecimal("123.456789");
BigDecimal roundedNumber = number.setScale(2, BigDecimal.ROUND_HALF_UP);

2.5.比较

  • compareTo(BigDecimal val):比较当前 BigDecimal对象与参数的大小关系。

  • equals(Object obj):比较当前 BigDecimal 对象与参数是否相等。

BigDecimal bigDecimal1 = new BigDecimal("123.456789");
BigDecimal bigDecimal2 = new BigDecimal("123.456789");
System.out.println(bigDecimal1.compareTo(bigDecimal2));
System.out.println(bigDecimal1.equals(bigDecimal2));

2.6.转换

  • intValue()、longValue()、floatValue()、doubleValue():将 BigDecimal 对象转换为对应的基本数据类型。

  • toBigInteger()、toBigIntegerExact():将 BigDecimal对象转换为 BigInteger对象。

BigDecimal bigDecimal = new BigDecimal("123.456789");
int i = bigDecimal.intValue();
float v = bigDecimal.floatValue();
double v1 = bigDecimal.doubleValue();
long l = bigDecimal.longValue();
BigInteger bigInteger = bigDecimal.toBigInteger();
BigInteger bigInteger1 = bigDecimal.toBigIntegerExact();

3.注意事项

BigDecimal虽然能杜绝运算过程中的精度丢失,但无法杜绝初始化过程中的精度丢失,例如:

BigDecimal bigDecimal1=new BigDecimal(1.2);
BigDecimal bigDecimal2=new BigDecimal(1.234);
System.out.println(bigDecimal1.add(bigDecimal2));

上面代码就会存在精度丢失,因为我们输入1.2和1.234后,输入的数据会转浮点数存在计算机的内存中,这种转换过程中,精度就已经丢失了,BigDecimal去内存中读这两个数时,读出来的就是精度丢失的数。

为了确保精度,尽量用字符串来初始化:

BigDecimal bigDecimal1=new BigDecimal("1.2");
BigDecimal bigDecimal2=new BigDecimal("1.234");
System.out.println(bigDecimal1.add(bigDecimal2));

4.底层实现原理

BigDecimal底层的代码可读性不是很好,这里直接给出底层实现原理的总结:

在BigDecimal内部,它使用一个整数数组来存储数值的每一位。通常情况下,数组的每个元素表示一组十进制数的位数,例如,数组的第一个元素表示最低位,第二个元素表示十位,以此类推。每个数组元素都是一个32位整数,即可以存储0到2^32-1之间的数值。

为了表示一个数值,BigDecimal还需要维护一些其他的信息,包括符号(正数、负数或零)、小数点的位置以及数值的精度。这些信息通过额外的变量来保存。

在进行数值的运算时,BigDecimal会根据操作的类型和需要的精度,对两个数值进行相应的运算,例如加法、减法、乘法和除法。运算的过程中,它会对两个数值的符号进行处理,并按照数学规则进行运算。对于除法运算,BigDecimal会通过精确的算法进行计算,避免了浮点数除法可能产生的精度损失。

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

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

相关文章

小马哥训练营-Java EE单体架构

什么是Servlet Servlet 是一种基于 Java 技术的 Web 组件,用于生成动态内容,由容器管理。类似于其他 Java 技术组件,Servlet 是平台无关的 Java 类组成,并且由 Java Web 服务器加载执行。通常情况,由 Servlet 容器提供…

(十一)CSharp-LINQ-查询表达式(2)

一、查询表达式 1、查询表达式的结构 查询表达式由 from 子句和查询主体组成。 子句必须按照一定的顺序出现。from 子句和 select…group 子句这两部分是必需的。其他子句是可选的。在 LINQ 查询表达式中,select 子句在表达式最后。可以有任意多的 from…let…wh…

Nginx服务器的六个修改小实验

一、Nginx虚拟主机配置 1.基于域名 (1)为虚拟主机提供域名解析 配置DNS 修改/etc/hosts文件 (2)为虚拟主机准备网页文档 #创建网页目录 mkdir -p /var/www/html/abc mkdir -p /var/www/html/def ​ #编写简易首页html文件 ec…

Finalshell安全吗?Xshell怎么样?

文章目录 一、我的常用ssh连接工具二、Xshell2.1 下载:认准官网2.2 Xshell 配置2.3 Xftp和WinSCP 一、我的常用ssh连接工具 之前讲过: 【服务器】远程连接选SSH(PUTTY、Finalshell、WinSCP) 还是 远程桌面(RDP、VNC、…

代码随想录训练营第四十二天|01背包、416.分割等和子集

01背包 代码随想录理论讲解 背包问题分类 01背包 问题描述 有n件物品和一个最多能背重量为w的背包。第i件物品的重量是weight[i],得到的价值是value[i]。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。 动归五部曲 确定dp数组及下…

基于java web高校社交系统 /springboot高校社交系统

摘 要 随着信息技术和网络技术的飞速发展,人类已进入全新信息化时代,传统管理技术已无法高效,便捷地管理信息。为了迎合时代需求,优化管理效率,各种各样的系统应运而生,各行各业相继进入信息管理时代&#…

CSS处理页面元素浮动的几个办法

CSS处理页面元素浮动的几个办法 不使用浮动的情况下&#xff0c;子盒子1和2分别在盒子1中占据一行的空间。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" cont…

Java 8新特性:方法引用的介绍与使用

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 1. 什么是方法引用&#xff1f; 2. 方法引用的…

【30天熟悉Go语言】9 Go函数全方位解析

作者&#xff1a;秃秃爱健身&#xff0c;多平台博客专家&#xff0c;某大厂后端开发&#xff0c;个人IP起于源码分析文章 &#x1f60b;。 源码系列专栏&#xff1a;Spring MVC源码系列、Spring Boot源码系列、SpringCloud源码系列&#xff08;含&#xff1a;Ribbon、Feign&…

【好书精读】网络是怎样连接的 之 数据收发完成之后 从服务器断开并删除套接字

&#xff08; 该图由AI制作 &#xff09; 目录 数据收发完成后协议栈要执行的操作 数据发送完毕后断开连接 删除套接字 数据收发操作小结 第一步是创建套接字 然后 客户端会向服务器发起连接操作 数据收发阶段 执行断开操作 数据收发完成后协议栈要执行的操作 数据发…

html_css模拟端午赛龙舟运动

文章目录 ⭐前言&#x1f496; 样式布局&#x1f496; 添加龙舟&#x1f496; 添加css_animation运动 ⭐结束 ⭐前言 大家好&#xff0c;我是yma16&#xff0c;本期给大家分享css实现赛龙舟运动。 &#x1f496; 样式布局 风格&#xff1a;卡通 首先采用一张包括水元素的照片…

液体泄露识别检测算法 监控识别管道液体泄漏

液体泄露识别检测算法通过 yolov8python网络模型技术&#xff0c;液体泄露识别检测算法对管道的液体泄露情况进行全天候不间断实时监测&#xff0c;检测到画面中管道设备液体泄露现象时&#xff0c;将自动发出警报提示相关人员及时采取措施。YOLOv8 算法的核心特性和改动可以归…

硬件入门之什么是二级管

硬件入门之什么是二级管 文章目录 硬件入门之什么是二级管一、二极管是什么&#xff1f;二极管在电路中的作用很广泛&#xff1a; 单向导电&#xff0c;续流&#xff0c;稳压等等 二、分类二极管实际应用场景二极管分类1.通用二极管2..肖特二极管 3.稳压二极管&#xff08;利用…

零基础学会python编程——输入 / 输出函数与变量

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​ 目录 前言 学习目标 一.输入与输出函数 1.print 函数 【例2-1】 【例2-2】 【例2-3】 …

深度详解Nginx正向代理与反向代理

正向代理和反向代理的概念 1、正向代理2、反面代理以租房为例解释正向代理和反向代理&#xff1f;正向代理和反向代理配置 1、正向代理 它的工作原理就像一个跳板,简单的说,我是一个用户,我访问不了某网站,但是我能访问一个代理服务器&#xff0c;这个代理服务器呢,他能访问那个…

一文弄懂git原理及相关操作

文章目录 前言Git 是什么&#xff1f;Git 与 SVN 的区别Git 快速入门Git 相关网站Git 工作流程Git 工作空间Git 文件状态 Git 安装在 Linux 上安装在 Mac 上安装在 Windows 上安装从源代码安装 Git 配置Git 常用命令git initgit clonegit addgit commitgit branchgit tag查看信…

字符设备驱动内部实现原理解析

字符设备驱动内部实现原理解析 一. 字符设备驱动对象内部实现原理解析二. 字符设备驱动的注册流程三. 代码示例 一. 字符设备驱动对象内部实现原理解析 用户层&#xff1a; ​ 当用户打开&#xff08;open&#xff09;一个文件时,会生成一个文件描述符表 内核层&#xff1a; 内…

极致呈现系列之:Echarts散点图的数据魔力

目录 什么是散点图散点图的特点及应用场景散点图的特点散点图的应用场景 Echarts中散点图的常用属性Vue3中创建散点图美化散点图样式 在数据分析和可视化过程中&#xff0c;散点图是一种常见且重要的工具。散点图可以帮助我们直观地观察两个变量之间的关系&#xff0c;并发现其…

MySQL实战解析底层---“order by“是怎么工作的

目录 前言 全字段排序 rowid排序 全字段排序 VS rowid排序 前言 在开发应用的时候&#xff0c;一定会经常碰到需要根据指定的字段排序来显示结果的需求以举例市民表为例&#xff0c;假设你要查询城市是“杭州”的所有人名字&#xff0c;并且按照姓名排序返回前1000个人的姓…

20230622作业:字符设备驱动内部实现原理及流程

1.1字符设备驱动内部实现原理 1>用户打开设备open("~/dev/mycdev",O_RDWR);("路径"&#xff0c;打开方式)2>在内核的虚拟文件系统层会同步执行sys_open函数,实现如下操作3>根据open函数的路径&#xff0c;找到struct inode结构体4>在struct…