浅谈BigDecimal精度丢失问题

文章目录

  • 浅谈BigDecimal精度丢失问题
    • 一. 简介
    • 二. 错误使用
    • 三. 原因分析
    • 四. 正确使用

一. 简介

​ Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数,但在实际应用中,可能需要对更大或者更小的数进行运算和处理。一般情况下,对于那些不需要准确计算精度的数字,我们可以直接使用Float和Double处理,但是Double.valueOf(String) 和Float.valueOf(String)会丢失精度。所以开发中,如果我们需要精确计算的结果,则必须使用BigDecimal类来操作。

二. 错误使用

在我们的日常开发中,对于金钱的处理我们都会使用BigDecimal进行处理,但是如果我们不熟悉使用的话,很容易出现如下的错误使用方式。
代码演示:


import java.math.BigDecimal;public class DecimalTest {public static void main(String[] args) {BigDecimal bd1 = new BigDecimal(0.1);System.out.println("bd1的值:"+bd1);}
}


从上面的执行可以看出,java中进行浮点数运算的时候,会出现丢失精度的问题。那么我们如果在进行价格计算的时候,就会出现问题。

三. 原因分析

计算机组成原理里面都有,它们的编码决定了这样的结果。
long可以准确存储19位数字,而double只能准确存储16位数字。

double由于有exp位,可以存16位以上的数字,但是需要以低位的不精确作为代价。如果需要高于19位数字的精确存储,则必须用BigInteger来保存,当然会牺牲一些性能。

源码注释解读:

 /*** Translates a {@code double} into a {@code BigDecimal} which* is the exact decimal representation of the {@code double}'s* binary floating-point value.  The scale of the returned* {@code BigDecimal} is the smallest value such that* <tt>(10<sup>scale</sup> &times; val)</tt> is an integer.* <p>* <b>Notes:</b>* <ol>* <li>* The results of this constructor can be somewhat unpredictable.* One might assume that writing {@code new BigDecimal(0.1)} in* Java creates a {@code BigDecimal} which is exactly equal to* 0.1 (an unscaled value of 1, with a scale of 1), but it is* actually equal to* 0.1000000000000000055511151231257827021181583404541015625.* This is because 0.1 cannot be represented exactly as a* {@code double} (or, for that matter, as a binary fraction of* any finite length).  Thus, the value that is being passed* <i>in</i> to the constructor is not exactly equal to 0.1,* appearances notwithstanding.** <li>* The {@code String} constructor, on the other hand, is* perfectly predictable: writing {@code new BigDecimal("0.1")}* creates a {@code BigDecimal} which is <i>exactly</i> equal to* 0.1, as one would expect.  Therefore, it is generally* recommended that the {@linkplain #BigDecimal(String)* <tt>String</tt> constructor} be used in preference to this one.** <li>* When a {@code double} must be used as a source for a* {@code BigDecimal}, note that this constructor provides an* exact conversion; it does not give the same result as* converting the {@code double} to a {@code String} using the* {@link Double#toString(double)} method and then using the* {@link #BigDecimal(String)} constructor.  To get that result,* use the {@code static} {@link #valueOf(double)} method.* </ol>** @param val {@code double} value to be converted to*        {@code BigDecimal}.* @throws NumberFormatException if {@code val} is infinite or NaN.*/public BigDecimal(double val) {this(val,MathContext.UNLIMITED);}
  • 第一段也说的很清楚它只能计算的无限接近这个数,但是无法精确到这个数。
  • 第二段则说,如果要想准确计算这个值,那么需要把double类型的参数转化为String类型的。并且使用BigDecimal(String)这个构造方法进行构造。去获取结果。

四. 正确使用

我们一般使用BigDecimal来解决商业运算上丢失精度的问题的时候,声明BigDecimal对象的时候一定要使用它构造参数为String的类型的构造器。

代码演示:

import java.math.BigDecimal;public class DecimalTest {public static void main(String[] args) {// 错误使用方式BigDecimal bd1 = new BigDecimal(0.1);System.out.println("bd1的值:"+bd1);// 正确使用方式BigDecimal bd2 = new BigDecimal("0.1");System.out.println("bd2的值:"+bd2);}
}

另外,BigDecimal所创建的是对象,我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。

BigDecimal精度丢失问题相关推荐

  1. 关于json 转换BigDecimal精度丢失问题

    今天在转换一个关于金额字段发现一个关于json转换的bug  目前尚未深入观察 问题: 如果金钱为bigdecimal json转换后不会丢失精度 但是通过@responsebody 返回到前端后发现 ...

  2. Java 避免精度丢失之BigDecimal 运算

    * 由于Java的简单类型不能够精确的对浮点数进行运算,这个工具类提供精确的浮点数运算,包括加减乘除和四舍五入 import java.math.BigDecimal; /** 计算工具类 */ pu ...

  3. Java中BigDecimal解决精度丢失问题

    1.我们先看一个例子 可以看到在Java中进行浮点数运算的时候,会出现丢失精度的问题.那么我们如果在进行商品价格计算的时候,就会出现问题.很有可能造成我们手中有0.06元,却无法购买一个0.05元和一 ...

  4. bigdecimal取小数部分_小数精度丢失问题分析和解决

    无论在什么业务中,钱?是非常重要的东西,对账的时候一定要对的上,不能这边少一分钱那边多一分钱.对于数值的计算,尤其是小数,floate和double都是禁止使用的. 阿里强制要求存放小数时使用 dec ...

  5. BigDecimal操作double、float精度丢失问题

    一.问题 最近使用BigDecimal进行数值加减运算的时候踩了一个小坑:BigDecimal操作double.float数值时精度丢失. 举个例子: public static void main( ...

  6. java中double类型精度丢失问题及解决方法

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 来源: https://blog.csdn.net/yacolsp ...

  7. 浮点数精度问题透析:小数计算不准确+浮点数精度丢失根源

    在知乎上上看到如下问题: 浮点数精度问题的前世今生? 1.该问题出现的原因 ? 2.为何其他编程语言,比如java中可能没有js那么明显 3.大家在项目中踩过浮点数精度的坑? 4.最后采用哪些方案规避 ...

  8. double operator[](int i)_java中double类型精度丢失问题及解决方法

    原文链接:https://blog.csdn.net/yacolspace/article/details/78287394 double类型数据加减操作精度丢失问题 今天在项目中用到double类型 ...

  9. python 浮点数精度丢失_浮点数精度问题透析:小数计算不准确+浮点数精度丢失根源...

    浮点数精度问题透析:小数计算不准确+浮点数精度丢失根源 无论在java python javaScript里面都存在 1+ 2!== 3 问题,这个问题的产生根源在于计算存储数字是二进制,对无限循环小 ...

最新文章

  1. Android 弱引用 (WeakReference)的使用
  2. STM32如何从串口接收数据,取出数据中的密码段再保存到flash中。
  3. Python的常见几道数学运算题
  4. UA MATH563 概率论的数学基础 鞅论初步10 Doob可选停止定理与一维随机游走的exiting time
  5. C语言第一行为N以下N行,C语言每日小练(四)——勇者斗恶龙
  6. 农行基于TFS工具的敏捷转型实践
  7. 怎么在html中加入pjax,pjax加载多说的三种方法
  8. 【2020-06-16】CentOS8下yum安装nginx,systemctl start nginx报错undefined symbol: FT_Done_MM_Var
  9. JS ||(或运算)详解
  10. 获取屏幕尺寸、状态栏、标题栏高度
  11. 2020家用千兆路由器哪款好_千兆路由器哪个好 2020年值得入手的家用千兆路由器推荐...
  12. Python学习手册之控制结构(二)
  13. 四、 按键控制流水灯的运行与暂停
  14. 名帖17 吴让之 篆书《吴让之篆书墨迹》
  15. 第5 部分 EIGRP
  16. 高手教你ie主页被篡改怎么办|加个参数永远不怕IE主页被修改
  17. jQuery实现的浮动广告
  18. 开源社区Github在2022年06月09日公测了三个新的成就徽章
  19. 建议Amazon卖家选择轻巧产品的原因
  20. LTE搜网注册流程(日志)

热门文章

  1. Java学习之旅(一):探索extends
  2. 【C++】1074:津津的储蓄计划(信息学奥赛)
  3. Android Studio第14课百度地图,获取相册和拍照
  4. ubuntu 编译opencv
  5. CorelDrawX8安装时提示已安装另一个版本
  6. spring启动时只执行一次的方法实现
  7. CPU卡加密系统与M1加密系统比较!
  8. Java应届生大学四年怎么做,可以毕业就进入华为工作,上个月成功拿到阿里P7offer
  9. 『每日AI』王劲离职景驰科技丨无人驾驶领域的领跑者还是叛逃者?
  10. 用户访问一个网站的过程描述