java浮点数精度损失原理和解决
来源:互联网 发布:网络咨询医生有前途吗 编辑:程序博客网 时间:2024/06/06 07:30
原理
浮点数会有精度损失,如下代码所示
public class NumTest { public static void main(String[] args) { double a =1; double b =0.99; System.out.println(a-b); }}
这段代码运行结果很简单,不是0.01么?!
在这一天之前如果问我结果是什么我也会毫不犹豫的答道0.01,然而真实的结果是:0.010 00000 00000 00009。
虽然运算结果不太对,但是这个结果和0.01相差不大会产生影响么?那看下面这一段代码:
public class NumTest { public static void main(String[] args) { double a =1; double b =0.99; System.out.println(a-b); if((a-b) == 0.01){ System.out.println("1 - 0.99 == 0.01"); }else{ System.out.println("1 - 0.99 != 0.01"); } }}
输出的结果也在意料之中:1 - 0.99 != 0.01
如果在程序中直接使用double会造成精度损失,极有可能对造成一些莫名奇妙的bug。
但是所有的浮点数都会有精度损失么?
package sort;public class NumTest { public static void main(String[] args) { double a = 0.5; double b = 0.25; System.out.println(a-b); if((a-b) == 0.25){ System.out.println("no problem"); }else{ System.out.println("has problem"); } }}
输出的结果是:no problem,也就是说double类型的0.5和0.25在运算的时候没有出现精度损失。
关于精度损失的原理可以很简单的讲,首先一个正整数在计算机中表示使用01010形式表示的,浮点数也不例外。
比如11,11除以2等于5余1
5除以2等于2余1
2除以2等于1余0
1除以2等于0余1
所以11二进制表示为:1011.
double类型占8个字节,64位,第1位为符号位,后面11位是指数部分,剩余部分是有效数字。
正整数除以2肯定会有个尽头的,之后二进制还原成十进制只需要乘以2即可。
举个例子:0.99用的有效数字部分,
0.99 * 2 = 1+0.98 –> 1
0.98 * 2 = 1+ 0.96 –> 1
0.96 * 2 = 1+0.92 – >1
0.92 * 2 = 1+0.84 – >1
……………
这样周而复始是没法有尽头的,而double有效数字有限,所以必定会有损失,所以二进制无法准确表示0.99,就像十进制无法准确表示1/3一样。
解决方案
一般遇到这种需要用到浮点数运算的地方都可以使用java.math.BigDecimal。
首先需要注意的是,直接使用字符串来构造BigDecimal是绝对没有精度损失的,如果用double或者把double转化成string来构造BigDecimal依然会有精度损失,所以我觉得这种解决方法就是在数据库中就把浮点数用string来表示存放,涉及到运算直接用string构造double,否则肯定会有精度损失。
package sort;import java.math.BigDecimal;public class NumTest { public static void main(String[] args) { String a = "301353.0499999999883584678173065185546875"; double c = 301353.0499999999883584678173065185546875d; BigDecimal sa = new BigDecimal(a); BigDecimal sc = new BigDecimal(String.valueOf(c)); BigDecimal dc = new BigDecimal(Double.toString(c)); System.out.println("sa : "+ sa); System.out.println("sc : "+ sc); System.out.println("dc : "+ dc); }}
上述代码的输出结果是:
sa : 301353.0499999999883584678173065185546875
sc : 301353.05
dc : 301353.05
所以最好的方法是完全抛弃double,用string和java.math.BigDecimal。
- java浮点数精度损失原理和解决
- java浮点数精度损失原理和解决
- java 浮点数精度损失
- 浮点数操作精度损失
- 字符串转换为浮点数时如何避免精度损失
- 【Java】解决计算浮点数精度问题(BigDecimal)
- Java中解决浮点数精度的问题
- Java中解决浮点数精度的问题
- Java中解决浮点数精度的问题
- Java浮点数精度控制
- java 浮点数精度问题
- JAVA浮点数精度问题
- Java浮点数精度问题
- 浮点数和机器精度
- 单精度浮点数和双精度浮点数
- Python的浮点数损失精度问题(为什么说双精度浮点数有15位十进制精度)
- JAVA编程——论浮点运算损失精度问题
- 浮点型损失精度现象
- zoc7 使用指南 连接远程主机
- 快速排序
- VS2015快捷键使用学习总结
- Linux 统计文档中各个字母出现的次数,显示各个字母出现的频率
- ROS tf知识整理
- java浮点数精度损失原理和解决
- JVM -verbose参数详解
- 百度地图添加marker,并增加左键点击,右键菜单,文本窗等功能
- caffe+win10+vs2013+Gpu配置记录
- SyntaxError: Missing parentheses in call to 'print'
- 1127. ZigZagging on a Tree (30)
- JavaScript 创建对象---原型模式
- Android 你应该知道的的应用冷启动过程分析和优化方案
- bzoj3876 [Ahoi2014&Jsoi2014]支线剧情