前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java中使用double转BigDecimal的问题

Java中使用double转BigDecimal的问题

作者头像
全栈程序员站长
发布2022-09-01 15:35:14
1.4K0
发布2022-09-01 15:35:14
举报
文章被收录于专栏:全栈程序员必看

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

先上结论:不要直接用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),我写了个例子试了一下:

代码语言:javascript
复制
     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.cn/141906.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年5月2,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档