Java中double转BigDecimal的注意事项

Java中double转BigDecimal的注意事项先上结论:不要直接用double变量作为构造BigDecimal的参数。 线上有这么一段Java代码逻辑:1,接口传来一个JSON串,里面有个数字:57.3。2,解析JSON并把这个数字保存在一个float变量。3,把这个float变量赋值给一个BigDecimal对象,用的是BigDecimal的double参数的构造:  newBigDecimal(double…

大家好,又见面了,我是你们的朋友全栈君。

先上结论:不要直接用double变量作为构造BigDecimal的参数。

 

线上有这么一段Java代码逻辑:

1,接口传来一个JSON串,里面有个数字:57.3。

2,解析JSON并把这个数字保存在一个float变量。

3,把这个float变量赋值给一个 BigDecimal对象,用的是BigDecimal的double参数的构造:

   new BigDecimal(double val)

4,把这个BigDecimal保存到MySQL数据库,字段类型是decimal(15,2)。

 

这段代码逻辑在线上跑了好久了,数据库保存的值是57.3也没什么问题,但是在今天debug的时候发现,第三步的BigDecimal对象保存的值并不是57.3,而是57.299999237060546875,很明显,出现了精度的问题。

至于数据库最终保存了正确的57.3完全是因为字段类型设置为2位小数,超过2位小数就四舍五入,所以才得到了正确的结果,相当于MySQL给我们把这个精度问题掩盖了。

 

总觉得这是个坑,所以研究了一下相关的知识。

首先是BigDecimal的double参数构造,在官方JDK文档中对这个构造是这么描述的:

public BigDecimal(double val)

Translates a double into a BigDecimal which is the exact decimal representation of the double’s binary floating-point value. The scale of the returned BigDecimal is the smallest value such that (10scale × val) is an integer.

Notes:

The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a 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 double (or, for that matter, as a binary fraction of any finite length). Thus, the value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding.

The String constructor, on the other hand, is perfectly predictable: writing new BigDecimal(“0.1”) creates a BigDecimal which is exactly equal to 0.1, as one would expect. Therefore, it is generally recommended that the String constructor be used in preference to this one.

When a double must be used as a source for a BigDecimal, note that this constructor provides an exact conversion; it does not give the same result as converting the double to a String using the Double.toString(double) method and then using the BigDecimal(String) constructor. To get that result, use the static valueOf(double) method.

Parameters:

val – double value to be converted to BigDecimal.

Throws:

NumberFormatException – if val is infinite or NaN.

翻译一下大概是这样的:

1,BigDecimal(double val)构造,用double当参数来构造一个BigDecimal对象。

2,但是这个构造不太靠谱(unpredictable),你可能以为BigDecimal(0.1)就是妥妥的等于0.1,但是你以为你以为的就是你以为的?还真不是,BigDecimal(0.1)这货实际上等于0.1000000000000000055511151231257827021181583404541015625,因为准确的来说0.1本身不能算是一个double(其实0.1不能代表任何一个定长二进制分数)。

3,BigDecimal(String val)构造是靠谱的,BigDecimal(“0.1”)就是妥妥的等于0.1,推荐大家用这个构造。

4,如果你非得用一个double变量来构造一个BigDecimal,没问题,我们贴心的提供了静态方法valueOf(double),这个方法跟new Decimal(Double.toString(double))效果是一样的。

 

说白了就是别直接拿double变量做参数,最好使用String类型做参数或者使用静态方法valueOf(double),我写了个例子试了一下:

         public static void main(String[] args) {



                   float a=57.3f;

                   BigDecimal decimalA=new BigDecimal(a);

                   System.out.println(decimalA);

                  

                   double b=57.3;

                   BigDecimal decimalB=new BigDecimal(b);

                   System.out.println(decimalB);

                  

                   double c=57.3;

                   BigDecimal decimalC=new BigDecimal(Double.toString(c));

                   System.out.println(decimalC);

                  

                   double d=57.3;

                   BigDecimal decimalD=BigDecimal.valueOf(d);

                   System.out.println(decimalD);

         }

 

输出结果:

57.299999237060546875

57.2999999999999971578290569595992565155029296875

57.3

57.3

以后还是尽量按照官方推荐的套路来,否则不知道什么时候又给自己挖坑了。

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/133915.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长

相关推荐

  • Android图形动画 使用ScaleAnimation

    Android图形动画 使用ScaleAnimation使用ScaleAnimation实现了一个类似于翻转的动画效果。感觉ScaleAnimation算是一个比较好用的动画类了,看了一下API感觉方法和构造方法也都很简单。就不再赘述太多直接上代码吧– 第一步:准备两张照片,放置在res/drawble下。首先在layout中写好布局文件,这里要用framelayout布局,让两张图片一张覆盖在另一张上。相信聪明的你…

    2022年8月31日
  • r语言求平均值_r语言计算中位数

    r语言求平均值_r语言计算中位数R中的统计分析通过使用许多内置函数来执行的,这些函数大部分是R基础包的一部分,并且它们将R向量与参数一起作为输入,并在执行计算后给出结果。先来看如何求平均值。平均值是通过取数值的总和并除以数据序列中的值的数量来计算,函数mean()用于在R中计算平均值,语法如下:mean(x,trim=0,na.rm=FALSE,…)参数描述如下:x-是输入向量。 t…

    2022年9月15日
  • Linux命令—tail 加过滤功能

    Linux命令—tail 加过滤功能tail-n 行数-f 文件夹路径以及名字,用于查看log 后面可以追加 |grep +名字 用于过滤ps aux|grep 文件 查看执行情况 tail-n40-f/home/logs/info.log|grepkeyword …

    2022年5月23日
  • KTT条件_kkt条件全称

    KTT条件_kkt条件全称上篇文章说了,拉格朗日乘子法,可以在等式约数的条件下,求得某函数f的极大或极小值,但是,等式约束只是不等式约束中的特例,如果我们遇到了不等式约束,该怎么办呢?本片不打算放图了,感觉完全可以接着上一篇继续搞!首先,对于等式约数,我们可以看成我们自变量可以取的点组成的几条线,也就是约束函数在某高度上的等高线。不过约束换成了不等式约束以后,此时约束就可能由“线”变成了面。但是,看上去需要考虑的取值…

    2022年10月21日
  • 音视频传输基本知识[通俗易懂]

    音视频传输基本知识[通俗易懂]音视频传输时的基本步骤:1.发起会话(Sip协议)2.编码(硬件编码、软件编码)3.传输(RTP)4.解码(硬件解码、软件解码)5结束会话(Sip协议)视频格式视频格式可以分为适合本地播放的本地影像视频和适合在网络中播放的网络流媒体影像视频两大类。尽管后者在播放的稳定性和播放画面质量上可能没有前者优秀,但网络流媒体影像视频的广泛传播性使之正被广泛应用于视频点播、网络演示

    2022年10月3日
  • C# 连接SQL Sever 数据库与数据查询实例 数据仓库

    C# 连接SQL Sever 数据库与数据查询实例 数据仓库大数据时代在编程可能需要用到一些文本内容,不可能全部写到代码里,不好更改,用户也不方便使用所以需要用到我们的数据库来保存这些数据,直接更改数据SQL:下载地址:https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads1.现在后打开选择登录:Windows身份验证2.创建登录的账号和密码(右键创建)3.创建数据库表右键新建…

    2022年6月7日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号