我的编程空间,编程开发者的网络收藏夹
学习永远不晚

BigDecimal遇到的坑有哪些

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

BigDecimal遇到的坑有哪些

这篇文章主要介绍“BigDecimal遇到的坑有哪些”,在日常操作中,相信很多人在BigDecimal遇到的坑有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”BigDecimal遇到的坑有哪些”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

避免用Double来进行运算

使用Double来计算,我们以为的算术运算和计算机计算的并不完全一直,这是因为计算机是以二进制存储数值的,我们输入的十进制数值都会转换成二进制进行计算,十进制转二进制再转换成十进制就不是原来那个十进制了,再也不是曾经那个少年了。举个例子:十进制的0.1转换成二进制是0.0  0011 0011  0011...(无数个0011),再转换成十进制就是0.1000000000000000055511151231,看到了吧,没有骗你的。

计算机无法精确地表达浮点数,这是不可避免的,这是为什么浮点数计算后精度损失的原因。

System.out.println(0.1+0.2); System.out.println(1.0-0.8); System.out.println(4.015*100); System.out.println(123.3/100);

BigDecimal遇到的坑有哪些

通过简单的例子,我们发现精度损失并不是很大,但是这并不代表我们可以使用,特别是电商类系统中,每天少说几百万的单量,每笔订单哪怕少计算一分钱,算下来也是一笔不小的金额,所以说,这不是个小事情,然后很多人就说,金额计算啊,你用BigDecimal啊,对的,这个没毛病,但是用了BigDecimal就完事大吉了吗?当问出这句话的时候,就说明这其中必有蹊跷。

BigDecimal你遇见过哪些坑?

还是通过一个简单的例子,计算上边例子中的运算,来看一下结果:

System.out.println(new BigDecimal(0.1).add(new BigDecimal(0.2))); System.out.println(new BigDecimal(1.0).subtract(new BigDecimal(0.8))); System.out.println(new BigDecimal(4.015).multiply(new BigDecimal(100))); System.out.println(new BigDecimal(123.3).divide(new BigDecimal(100)));

BigDecimal遇到的坑有哪些

我们发现使用了BigDecimal之后计算结果还是不精确,这里就要记住BigDecimal的第一个坑了:

BigDecimal来表示和计算浮点数的时候,要使用String的构造方法来初始化BigDecimal。

小的改进一下再来看看结果:

System.out.println(new BigDecimal("0.1").add(new BigDecimal("0.2"))); System.out.println(new BigDecimal("1.0").subtract(new BigDecimal("0.8"))); System.out.println(new BigDecimal("4.015").multiply(new BigDecimal("100"))); System.out.println(new BigDecimal("123.3").divide(new BigDecimal("100")));

BigDecimal遇到的坑有哪些

那么接下来一个问题,使用了BigDecimal就万事大吉了吗?并不是的!

接下来我们来看一下BigDecimal的源码,这里面有一个地方需要注意,先看图:

BigDecimal遇到的坑有哪些

注意看这两个属性,scale表示小数点右边几位,precision表示精度,就是我们常说的有效长度。

前边我们已经知道,BigDecimal必须传入字符串类型数值,那么如果我们现在是一个Double类型数值,该如何操作呢?通过一个简单的测试我们来看一下:

 private static void testScale() {      BigDecimal bigDecimal1 = new BigDecimal(Double.toString(100));      BigDecimal bigDecimal2 = new BigDecimal(String.valueOf(100d));      BigDecimal bigDecimal3 = BigDecimal.valueOf(100d);      BigDecimal bigDecimal4 = new BigDecimal("100");      BigDecimal bigDecimal5 = new BigDecimal(String.valueOf(100));       print(bigDecimal1);      print(bigDecimal2);      print(bigDecimal3);      print(bigDecimal4);      print(bigDecimal5);      }  private static void print(BigDecimal bigDecimal) {         System.out.println(String.format("scale %s precision %s result %s", bigDecimal.scale(), bigDecimal.precision(), bigDecimal.multiply(new BigDecimal("1.001")))); }

run一下我们发现,以上前三种方式是将double转换成BigDecimal之后,得到的BigDecimal的scale都是1,precision都是4,后两种方式的toString方法得到的scale都是0,precision都是3,与1.001进行乘运算后,我们发现,scale是两个数的scale相加的结果。

BigDecimal遇到的坑有哪些

我们在处理浮点数的字符串的时候,应该显式的方式通过格式化表达式或者格式化工具来明确小数位数和舍入方式。

浮点数的舍入和格式化该如何选择?

我们首先来看看使用String.format的格式化舍入,会有什么结果,我们知道浮点数有double和float两种,下边我们就用这两种来举例子:

double num1 = 3.35; float num2 = 3.35f; System.out.println(String.format("%.1f", num1)); System.out.println(String.format("%.1f", num2));

BigDecimal遇到的坑有哪些

得到的结果似乎与我们的预期有出入,其实这个问题也很好解释,double和float的精度是不同的,double的3.35相当于3.350000000000000088817841970012523233890533447265625,而float的3.35相当于3.349999904632568359375,String.format才有的又是四舍五入的方式舍入,所以精度问题和舍入方式就导致了运算结果与我们预期不同。

Formatter类中默认使用的是HALF_UP的舍入方式,如果我们需要使用其他的舍入方式来格式化,可以手动设置。

到这里我们就知道通过String.format的方式来格式化这条路坑有点多,所以,「浮点数的字符串格式化还得要使用BigDecimal来进行」。

来,上代码,测试一下究竟是不是那么回事:

BigDecimal num1 = new BigDecimal("3.35"); //小数点后1位,向下舍入 BigDecimal num2 = num1.setScale(1, BigDecimal.ROUND_DOWN); System.out.println(num2); //小数点后1位,四舍五入 BigDecimal num3 = num1.setScale(1, BigDecimal.ROUND_HALF_UP); System.out.println(num3); 输入结果: 3.3 3.4

这次得到的结果与我们预期一致。

BigDecimal不能使用equals方法比较?

我们都知道,包装类的比较要使用equals,而不能使用==,那么这一条在Bigdecimal中也适用吗?数据说话,简单的一个测试来说明:

System.out.println(new BigDecimal("1").equals(new BigDecimal("1.0"))) 结果:false

按照我们的理解1和1.0是相等的,也应该是相等的,但是Bigdecimal的equals在比较中不只是比较了value,还比较了scale,我们前边说了scale是小数点后的位数,明显两个值的小数点后位数不一样,所以结果为false。

实际的使用中,我们常常是只希望比较两个BigDecimal的value,这里就要注意,要使用compareTo方法:

System.out.println(new BigDecimal("1").compareTo(new BigDecimal("1.0"))) 结果:true

到此,关于“BigDecimal遇到的坑有哪些”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

BigDecimal遇到的坑有哪些

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

使用recvfrom函数遇到的坑有哪些

使用recvfrom函数时可能会遇到以下几个常见的问题:1. 阻塞问题:recvfrom函数默认是阻塞的,即当没有收到数据时,程序会一直阻塞在该函数处,直到有数据到达。如果需要设置为非阻塞模式,可以使用fcntl函数将套接字设置为非阻塞。2
2023-08-24

Android Studio升级到3.0后遇到的坑有哪些

这篇文章主要介绍Android Studio升级到3.0后遇到的坑有哪些,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!第一坑、必须升级gradle到4.0以上相信这个大坑,一般使用as的人都会解决了,所以就不多说第二
2023-05-30

使用try-catch-finally常遇到的坑有哪些

本篇内容主要讲解“使用try-catch-finally常遇到的坑有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“使用try-catch-finally常遇到的坑有哪些”吧!坑1:final
2023-06-15

mysql中timestamp比较查询遇到的坑有哪些

这篇文章主要介绍mysql中timestamp比较查询遇到的坑有哪些,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!timestamp比较查询遇到的坑要求mysql建表的时候update_time 为timestamp
2023-06-21

微信小程序开发时遇到的坑有哪些

这篇文章主要讲解了“微信小程序开发时遇到的坑有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“微信小程序开发时遇到的坑有哪些”吧!最近参与开发了公司的第一款小程序,开发体验基本类似于基于w
2023-06-13

mybatis if test判断BigDecimal遇到的坑及解决方法是什么

这篇“mybatis if test判断BigDecimal遇到的坑及解决方法是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看
2023-07-05

Python分布式进程中会遇到的坑都有哪些呢

Python分布式进程中会遇到的坑都有哪些呢,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。小惊大怪你是不是在用Python3或者在windows系统上编程?最重要的是你对进程和
2023-06-16

使用RxJava中遇到的一些”坑“

前言大家越用RxJava,越觉得它好用,所以不知不觉地发现代码里到处都是RxJava的身影。然而,RxJava也不是银弹,其中仍然有很多问题需要解决。这里,我简单地总结一下自己遇到的一些“坑”,内容上可能会比较松散。一、考虑主线程的切换Rx
2023-05-31

stm32+FreeRTOS遇到的坑

问题 最近把项目移植进FreeRTOS时,发现开始任务都不能启动; 机器是stm32f407,使用的arm固件和FreeRTOS都是最新版本; 裸机运行没有问题,但是使用任务运行就运行不了; 排查 首先尝试了教程用的点灯代码,发现可以正常运
2023-08-30

elasticsearch7.5安装遇到的坑

没错,从零开始的elasticsearch搭建教程开始了!h"h **原文:https://www.cnblogs.com/heermayou/p/12670662.html那么首先假设 你已经装好了一个CentOS系统 ,我的是centos6.7的 1.到官
elasticsearch7.5安装遇到的坑
2017-03-23

Linux实践中使用重定向和管道符遇到的坑有哪些

这篇文章给大家介绍Linux实践中使用重定向和管道符遇到的坑有哪些,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。我很喜欢 Linux 系统,尤其是 Linux 的一些设计很漂亮,比如可以将一些复杂的问题分解成若干小问
2023-06-15

CSS中遇到有哪些问题

这篇文章主要为大家展示了“CSS中遇到有哪些问题”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“CSS中遇到有哪些问题”这篇文章吧。一、IE浏览器模式Hack标识 1、css hack标识 代码如
2023-06-08

ubuntu安装mysql遇到的坑---

最近学习大数据,涉及到hive的部分需要安装mysql,于是就在linux环境下尝试安装,对于我这个linux小白来说,中间遇到很多坑爹问题,在这里做一个记录。我参考的mysql安装博客: https://www.cnblogs.com/f
2023-01-30

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录