浅谈java的浮点数精度问题及如何解决精度缺失问题

上传人:ji****72 文档编号:37964068 上传时间:2018-04-25 格式:DOC 页数:10 大小:63.50KB
返回 下载 相关 举报
浅谈java的浮点数精度问题及如何解决精度缺失问题_第1页
第1页 / 共10页
浅谈java的浮点数精度问题及如何解决精度缺失问题_第2页
第2页 / 共10页
浅谈java的浮点数精度问题及如何解决精度缺失问题_第3页
第3页 / 共10页
浅谈java的浮点数精度问题及如何解决精度缺失问题_第4页
第4页 / 共10页
浅谈java的浮点数精度问题及如何解决精度缺失问题_第5页
第5页 / 共10页
点击查看更多>>
资源描述

《浅谈java的浮点数精度问题及如何解决精度缺失问题》由会员分享,可在线阅读,更多相关《浅谈java的浮点数精度问题及如何解决精度缺失问题(10页珍藏版)》请在金锄头文库上搜索。

1、java float double 精度为什么会丢失?浅谈 java 的浮点数精度问题由于对 float 或 double 的使用不当,可能会出现精度丢失的问题。问题大概情况可以通过如下代码理解:java view plaincopyprint?1.public class FloatDoubleTest 2.public static void main(String args) 3.float f = 20014999; 4.double d = f; 5.double d2 = 20014999; 6.System.out.println(“f=“ + f); 7.System.out.

2、println(“d=“ + d); 8.System.out.println(“d2=“ + d2); 9. System.out.println(0.05+0.01); System.out.println(1.0-0.42); System.out.println(4.015*100); System.out.println(123.3/100); 10. 11. public class FloatDoubleTest public static void main(String args) float f = 20014999; double d = f; double d2 = 2

3、0014999; System.out.println(“f=“ + f); System.out.println(“d=“ + d); System.out.println(“d2=“ + d2); 得到的结果如下:f=2.0015E7d=2.0015E7d2=2.0014999E7从输出结果可以看出 double 可以正确的表示 20014999 ,而 float 没有办法表示20014999 ,得到的只是一个近似值。这样的结果很让人讶异。20014999 这么小的数字在 float 下没办法表示。于是带着这个问题,做了一次关于 float 和 double 学习,做个简单分享,希望有助于

4、大家对 java 浮点数的理解。关于 java 的 float 和 doubleJava 语言支持两种基本的浮点类型: float 和 double 。java 的浮点类型都依据 IEEE 754 标准。IEEE 754 定义了 32 位和 64 位双精度两种浮点二进制小数标准。IEEE 754 用科学记数法以底数为 2 的小数来表示浮点数。32 位浮点数用 1 位表示数字的符号,用 8 位来表示指数,用 23 位来表示尾数,即小数部分。作为有符号整数的指数可以有正负之分。小数部分用二进制(底数 2 )小数来表示。对于 64 位双精度浮点数,用 1 位表示数字的符号,用 11 位表示指数,52

5、 位表示尾数。如下两个图来表示:float(32 位):double(64 位):都是分为三个部分:(1) 一个单独的符号位 s 直接编码符号 s 。(2)k 位的幂指数 E ,移码表示 。(3)n 位的小数,原码表示 。那么 20014999 为什么用 float 没有办法正确表示?结合 float 和 double 的表示方法,通过分析 20014999 的二进制表示就可以知道答案了。以下程序可以得出 20014999 在 double 和 float 下的二进制表示方式。java view plaincopyprint?1.public class FloatDoubleTest3 2.

6、public static void main(String args) 3.double d = 8; 4.long l = Double.doubleToLongBits(d); 5.System.out.println(Long.toBinaryString(l); 6.float f = 8; 7.int i = Float.floatToIntBits(f); 8.System.out.println(Integer.toBinaryString(i); 9. 10. public class FloatDoubleTest3 public static void main(Stri

7、ng args) double d = 8; long l = Double.doubleToLongBits(d); System.out.println(Long.toBinaryString(l); float f = 8; int i = Float.floatToIntBits(f); System.out.println(Integer.toBinaryString(i); 输出结果如下:Double:100000101110011000101100111100101110000000000000000000000000000Float:1001011100110001011001

8、111001100对于输出结果分析如下。对于都不 double 的二进制左边补上符号位 0 刚好可以得到 64 位的二进制数。根据 double 的表示法,分为符号数、幂指数和尾数三个部分如下:0 10000010111 0011000101100111100101110000000000000000000000000000对于 float 左边补上符号位 0 刚好可以得到 32 位的二进制数。 根据 float 的表示法, 也分为 符号数、幂指数和尾数三个部分如下 :0 10010111 00110001011001111001100绿色部分是符号位,红色部分是幂指数,蓝色部分是尾数。对比可

9、以得出:符号位都是 0 ,幂指数为移码表示,两者刚好也相等。唯一不同的是尾数。在 double 的尾数为: 001100010110011110010111 0000000000000000000000000000 ,省略后面的零,至少需要 24 位才能正确表示 。而在 float 下面尾数为: 00110001011001111001100 ,共 23 位。为什么会这样?原因很明显,因为 float 尾数 最多只能表示 23 位,所以 24 位的 001100010110011110010111 在 float 下面经过四舍五入变成了 23 位的 0011000101100111100110

10、0 。所以 20014999 在 float 下面变成了 20015000 。也就是说 20014999 虽然是在 float 的表示范围之内,但 在 IEEE 754 的 float 表示法精度长度没有办法表示出 20014999 ,而只能通过四舍五入得到一个近似值。总结:浮点运算很少是精确的,只要是超过精度能表示的范围就会产生误差。往往产生误差不是因为数的大小,而是因为数的精度。因此,产生的结果接近但不等于想要的结果。尤其在使用 float 和 double 作精确运算的时候要特别小心。可以考虑采用一些替代方案来实现。如通过 String 结合 BigDecimal 或者通过使用 long

11、 类型来转换。解决方案:package A;import java.math.BigDecimal; /* * 由于 Java 的简单类型不能够精确的对浮点数进行运算,这个工具类提供精 * 确的浮点数运算,包括加减乘除和四舍五入。 */ public class Arith /默认除法运算精度 private static final int DEF_DIV_SCALE = 10; /这个类不能实例化 private Arith() /* * 提供精确的加法运算。 * param v1 被加数 * param v2 加数 * return 两个参数的和 */ public static dou

12、ble add(double v1,double v2) BigDecimal b1 = new BigDecimal(Double.toString(v1); BigDecimal b2 = new BigDecimal(Double.toString(v2); return b1.add(b2).doubleValue(); /* * 提供精确的减法运算。 * param v1 被减数 * param v2 减数 * return 两个参数的差 */ public static double sub(double v1,double v2) BigDecimal b1 = new BigD

13、ecimal(Double.toString(v1); BigDecimal b2 = new BigDecimal(Double.toString(v2); return b1.subtract(b2).doubleValue(); /* * 提供精确的乘法运算。 * param v1 被乘数 * param v2 乘数 * return 两个参数的积 */ public static double mul(double v1,double v2) BigDecimal b1 = new BigDecimal(Double.toString(v1); BigDecimal b2 = new

14、BigDecimal(Double.toString(v2); return b1.multiply(b2).doubleValue(); /* * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 * 小数点以后 10 位,以后的数字四舍五入。 * param v1 被除数 * param v2 除数 * return 两个参数的商 */ public static double div(double v1,double v2) return div(v1,v2,DEF_DIV_SCALE); /* * 提供(相对)精确的除法运算。当发生除不尽的情况时,由 scale 参数指 * 定

15、精度,以后的数字四舍五入。 * param v1 被除数 * param v2 除数 * param scale 表示表示需要精确到小数点以后几位。 * return 两个参数的商 */ public static double div(double v1,double v2,int scale) if(scale0) throw new IllegalArgumentException( “The scale must be a positive integer or zero“); BigDecimal b1 = new BigDecimal(Double.toString(v1); BigDecimal b2 = new BigDecimal(Double.toStr

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 行业资料 > 其它行业文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号