【1】Java中double转BigDecimal的注意事项
项目遇到该问题
先上结论:不要直接用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://blog.csdn.net/lkforce/article/details/81564927
【1】Java中double转BigDecimal的注意事项的更多相关文章
- Java中double转BigDecimal的注意事项
先上结论:不要直接用double变量作为构造BigDecimal的参数! 线上有这么一段Java代码逻辑: 1,接口传来一个JSON串,里面有个数字:57.3. 2,解析JSON并把这个数字保存在一个 ...
- Java中double类型的数据精确到小数点后两位
Java中double类型的数据精确到小数点后两位 多余位四舍五入,四种方法 一: double f = 111231.5585;BigDecimal b = new BigDecimal(f); d ...
- Java中double变量精确到小数点后几(2)位
import java.math.BigDecimal; import java.text.NumberFormat; public class Java中double类型的数据精确到小数点后两位 { ...
- java中double和float精度丢失问题及解决方法
在讨论两位double数0.2和0.3相加时,毫无疑问他们相加的结果是0.5.但是问题总是如此吗? 下面我们让下面两个doubles数相加,然后看看输出结果: @Test public void te ...
- java中double变量保留小数问题
(转载自玄影池扁舟) 做java项目的时候可能经常会遇到double类型变量保留小数的问题,下面便把我的经验做个简短的总结: java中double类型变量保留小数问题大体分两种情况: (一):小数点 ...
- java中如何使用BigDecimal使得Double类型保留两位有效数字
一.场景:从数据表中读出Decimal类型的数据直接塞给Double类型的对象时,并不会有什么异常. 如果要再此基础上计算,就会发生异常. 比如:读出数据为0.0092,将其乘以100,则变成了0.9 ...
- 关于java中Double类型的运算精度问题
标题 在Java中实现浮点数的精确计算 AYellow(原作) 修改 关键字 Java 浮点数 精确计算 问题的提出:如果我们编译运行下面这个程序会看到什么?publi ...
- Java中Double类型计算问题
public class Test{ public static void main(String args[]){ System.out.println(0.05+0.01); ...
- 如何使java中double类型不以科学计数法表示
在java中,把一个double或者BigDecimal的小数转换为字符串时,经常会用科学计数法表示,而我们一般不想使用科学计数法,可以通过:DecimalFormat a = new Decimal ...
随机推荐
- Minimum number of steps CodeForces - 805D(签到题)
D. Minimum number of steps time limit per test 1 second memory limit per test 256 megabytes input st ...
- SpringMVC的缓存对静态资源的影响 304 Not Modified
我们知道在springmvc的配置中,可以添加缓存,但是缓存到底对静态资源有什么影响? 测试 没有添加缓存 <mvc:resources mapping="/image/**" ...
- PHUML 生成UML类图操作流程
项目基础阶段: 安装svn,因为托管在svn平台上: 项目下载到本地,并切换到对应目录(如:F:\wwwroot\phuml.git\trunk\src\app): svn checkout http ...
- 【JVM】查看JVM加载的类及类加载器的方法
查看JVM加载了哪些类 java -verbose[:class|gc|jni] 在输出设备上显示虚拟机运行信息. java -verbose:class 在程序运行的时候有多少类被加载!你可以用ve ...
- 【Hihocoder1413】Rikka with String(后缀自动机)
[Hihocoder1413]Rikka with String(后缀自动机) 题面 Hihocoder 给定一个小写字母串,回答分别把每个位置上的字符替换为'#'后的本质不同的子串数. 题解 首先横 ...
- 每天一个linux命令(1):wc命令
Linux系统中的wc(Word Count)命令的功能为统计指定文件中的字节数.字数.行数,并将统计结果显示输出. 1.命令格式: wc [选项]文件... 2.命令功能: 统计指定文件中的字节数. ...
- 转----------数据库常见笔试面试题 - Hectorhua的专栏 - CSDN博客
数据库基础(面试常见题) 一.数据库基础 1. 数据抽象:物理抽象.概念抽象.视图级抽象,内模式.模式.外模式 2. SQL语言包括数据定义.数据操纵(Data Manipulation),数据控制( ...
- VS编译LESS插件
1. LESS 用LESS写CSS可以用写程序代码的习惯写CSS.用了之后写CSS的效率会提高很多. 2.解释LESS 写出来的文件扩展名是.less,要运行的话,先解释成正常的CSS文件. 3. ...
- LaTeX教程与下载
LaTeX教程与下载如下: 其实,下载好CTEX 的步骤只有三步.第一步下载好CTEX ,第二步下载编辑器Texstudio ,第三步安装配置TexStudio 详细步骤: 第一步:下载CTEX La ...
- Java 破解谷歌翻译api,可以实现程序自动化翻译文章
1 原理:查看谷歌翻译网站,输入需要翻译的文字,选择语言得到翻译后的文字,发送异步请求参数返回结果.java使用httpclient发送请求,实现使用代码翻译文章的功能. 2 下载代码后,测试入口 ...