java double类型运算问题
2016-04-13 14:12
190 查看
问题重现:
运行上面的语句,最终的结果是:
很奇怪,并不是想象中的0.3,错误在哪里?
原因:这其实是计算机内部机制导致的问题,具体就是计算机中存储浮点数的机制,导致浮点数如果参与了运算,那么就可能会丧失精度,产生预期之外的结果,当然这里只是可能,有以下运算确实会恰巧复合预期结果。
那么结论:即尽量不要用double或者float来进行精确运算,会丧失精度。double和float适合科学计算,bigdecimal才适合精确计算。构建bigdecimal用string的参数。所谓的科学计算就是会算出很长的小数,最后按需求取舍就可以了。比如天文学或者化学中的质量测定,都不需要特别精确,取小数点后多少多少位就可以了。但如果是经融或者医疗领域,那就必须精确,不能取舍。
计算机存储浮点数原理:
正数存储就是补码(取反加一)。
浮点数在IEEE中也有详细的表示方式。大致是最高位表示正负,中间的几位表示尾数,最后的几位表示指数。
具体过程,首先拿到一个十进制的小数,
1,先将其转换为二进制的小数,整数部分除二取余法,小数部分则是乘二取整法;
2,移位,使得小数点的左边只有一个1,然后记下移动了多少位,假设是n位,那么指数部分就是n的二进制表示,当然,n可正可负;
3,根据正负设置符号位
4,取小数点后面的尾数设置尾数位,因为移位后小数点前面只有一个1,所以这个1不用记录,只要记录小数部分即可;
5,记录指数部分;
这就是double或者float在底层的实现。
从上面的过程可以知道,在将一个十进制的小数的小数部分转换为二进制的小数时,除非最后的一位是5,否则是不可能乘尽的,也就意味着这个十进制的小数是无法用二进制来精确表示的,如果double参与了运算,那么结果肯定有很大的概率不是精确的。这就解释了开始的奇怪结果。要想精确计算最好采用bigdecimal。但是,如果double没有参与运算,直接打印,结果却没有任何问题,这个还没有深究过。
double i = 0.1; System.out.println(i+i+i);
运行上面的语句,最终的结果是:
很奇怪,并不是想象中的0.3,错误在哪里?
原因:这其实是计算机内部机制导致的问题,具体就是计算机中存储浮点数的机制,导致浮点数如果参与了运算,那么就可能会丧失精度,产生预期之外的结果,当然这里只是可能,有以下运算确实会恰巧复合预期结果。
那么结论:即尽量不要用double或者float来进行精确运算,会丧失精度。double和float适合科学计算,bigdecimal才适合精确计算。构建bigdecimal用string的参数。所谓的科学计算就是会算出很长的小数,最后按需求取舍就可以了。比如天文学或者化学中的质量测定,都不需要特别精确,取小数点后多少多少位就可以了。但如果是经融或者医疗领域,那就必须精确,不能取舍。
计算机存储浮点数原理:
正数存储就是补码(取反加一)。
浮点数在IEEE中也有详细的表示方式。大致是最高位表示正负,中间的几位表示尾数,最后的几位表示指数。
具体过程,首先拿到一个十进制的小数,
1,先将其转换为二进制的小数,整数部分除二取余法,小数部分则是乘二取整法;
2,移位,使得小数点的左边只有一个1,然后记下移动了多少位,假设是n位,那么指数部分就是n的二进制表示,当然,n可正可负;
3,根据正负设置符号位
4,取小数点后面的尾数设置尾数位,因为移位后小数点前面只有一个1,所以这个1不用记录,只要记录小数部分即可;
5,记录指数部分;
这就是double或者float在底层的实现。
从上面的过程可以知道,在将一个十进制的小数的小数部分转换为二进制的小数时,除非最后的一位是5,否则是不可能乘尽的,也就意味着这个十进制的小数是无法用二进制来精确表示的,如果double参与了运算,那么结果肯定有很大的概率不是精确的。这就解释了开始的奇怪结果。要想精确计算最好采用bigdecimal。但是,如果double没有参与运算,直接打印,结果却没有任何问题,这个还没有深究过。
相关文章推荐
- Java仿12306图片验证码
- Spring和ThreadLocal
- RPC小例子解决Exception in thread "main" java.lang.reflect.UndeclaredThrowableException
- SpringMVC环境搭建
- 项目移植过程中报:“Project facet Java version 1.7 is not supported.” 错误
- Java并发编程:Thread类的使用(详解)
- java 中\b \t \n \f \r \" \
- 现实JAVAEE开发中最常用到的技术和工具
- eclipse hadoop设置报错 9000 failed on connection exception
- 配置hadoop-1.2.1 eclipse开发环境 Run as hadoop
- 启动hadoop NoClassDefFoundError: javax/net/SocketFactory
- hadoop 运行java 清洗数据 报错Failed to set permissions of path: \tmp\...
- java ArrayList的应用
- eclipse 向HDFS中写入文件报错 Permission denied
- Eclipse 常用快捷键 非常实用
- Java Enum的多态性
- SWT或eclipse相关下载地址
- Java设计模式(一) Adapter(适配器)模式及I/O实例引申
- org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [com.XXX.util.spri
- Java 开发必装的 IntelliJ IDEA 插件