Java中使用double转BigDecimal的问题

Java中使用double转BigDecimal的问题先上结论:不要直接用double变量作为构造BigDecimal的参数。线上有这么一段Java代码逻辑:1,接口传来一个JSON串,里面有个数字:57.3。2,解析JSON并把这个数字保存在一个float变量。3,把这个float变量赋值给一个BigDecimal对象,用的是BigDecimal的double参数的构造:newBigDecimal(doubleval)4,把这个BigDecimal保存到MySQL数据库,字段类型是decimal(15,2)。…

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

先上结论:不要直接用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/141906.html原文链接:https://javaforall.net

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


相关推荐

  • java redis模糊查询_Redis模糊查询「建议收藏」

    java redis模糊查询_Redis模糊查询「建议收藏」最近使用Redis优化项目功能,其中有一部分为模糊查询,找了很多帖子,也没有找到很好的解决方案和思路,最终皇天不负有心人啊,终于让我找到了!!!可以通过Redis中keys命令进行获取key值,具体命令格式:keyspattern文中提到redis中允许模糊查询的有3个通配符,分别是:*,?,[]其中:*:通配任意多个字符?:通配单个字符[]:通配括号内的某一个字符===============…

    2022年5月29日
    40
  • msfconsole search_msfconsole下载

    msfconsole search_msfconsole下载msfconsole启动msf控制台后└─msfconsole2⨯…dBBBBBBbdBBBPdBBBBBBPdBBBBBb.o’dB’BBPdB’dB’dB’d…

    2022年9月6日
    2
  • pytest指定用例_文件夹排列顺序自定义

    pytest指定用例_文件夹排列顺序自定义前言测试用例在设计的时候,我们一般要求不要有先后顺序,用例是可以打乱了执行的,这样才能达到测试的效果.有些同学在写用例的时候,用例写了先后顺序,有先后顺序后,后面还会有新的问题(如:上个用例返回

    2022年7月29日
    0
  • 程序员常说的外包公司到底是什么意思_程序员项目外包

    程序员常说的外包公司到底是什么意思_程序员项目外包程序员工作的企业有好几种类型,比如说互联网企业,传统企业,还有外包公司,这几种类型的企业不论是工作性质还是福利待遇都有差异。都说外包公司不好,今天就来说说什么是外包公司。外包公司到底是什么?为了更好地分析,我们需要了解什么是外包。外包是一种将目标,委托给其他组织的管理模型。外包有很多种,如项目外包、产品外包、工程外包等等。而我们最为关心的,则是人力资源外包。这样说比较抽象,我来举个例子。项目外包:为了完成某个项目,出于进度、成本,甚至是风险转移的考量,将项目拆分一部分(如非核心部

    2022年9月30日
    0
  • 卷积 bn_卷积积分实验

    卷积 bn_卷积积分实验1.为什么要合并BN层在训练深度网络模型时,BN(BatchNormalization)层能够加速网络收敛,并且能够控制过拟合,一般放在卷积层之后。BN层将数据归一化后,能够有效解决梯度消失与梯度爆炸问题。虽然BN层在训练时起到了积极作用,然而,在网络前向推断时多了一些层的运算,影响了模型的性能,且占用了更多的内存或者显存空间。目前,很多先进的网络模型(ResNet,MobileN…

    2022年10月14日
    0
  • XML格式化工具类(java)

    XML格式化工具类(java)下面是完整的代码importorg.apache.catalina.tribes.membership.StaticMember;importorg.apache.xml.serialize.OutputFormat;importorg.apache.xml.serialize.OutputFormat;importorg.apache.xml.serialize.XMLSeria…

    2022年7月16日
    22

发表回复

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

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