精确计算java中float和double的精度

[本文相关的代码放在github上,地址为:https://github.com/VigourJiang/StructuredFloat]

Java中double类型的格式是遵循IEEE 754标准的。尽管数学意义上的小数是连续的,但double仅仅能表示其中的一些离散点,把这些离散点组成的集合记为S,S的大小还是有限的。如果要保存的小数P刚好在集合S内,那么double类型就能精确的表示P;否则double类型只能从集合S中找一个与P最近的离散点P‘代替P。

以上表述对于float也成立。IEEE 754中float和double的表示策略完全相同,区别仅仅体现在各个字段(指数字段、小数字段)的bit数量不同。

也就是说,float和double都是不精确的,因此偶尔会有一些奇怪的事情发生:

       double d = 1e16d;

       double d2 = d +1.0d - d;

       // 以下代码输出0.0,而不是1.0
       System.out.println(d2);

上述结果也许并不有趣,因为在学C语言的时候,你的老师就可能提醒过你。但有趣的是,float和double究竟有多不精确?给定一个double d = XXX,与d最接近的另外两个double的数值是多少?

我用Java写了一个解析原始数据类型float和double的类StructuredFloat,给定一个float或者double数值P,它可以计算出与P的绝对值最近的、可以被float/double表示的浮点数。下面是用法:

	    double cur = 3.23d; // any valid double value
	    StructuredFloat sd = com.vigour.StructuredFloat.StructedFloatBuilder.buildDouble(cur);
	    StructuredFloat smaller = sd.absSmaller();
	    StructuredFloat bigger = sd.absBigger();

	    if(smaller != null){
	      double smaller_double = smaller.getBigDecimal().doubleValue();
	      // now you get the nearest double value whose absolute value is smaller
	    }
	    if(bigger!= null){
	      double bigger_double = bigger.getBigDecimal().doubleValue();
	      // now you get the nearest double value whose absolute value is bigger
	    }

下面是一些有趣的输出,可以看到,在1e16d附近double的精度就小于1了,在1e7f(一千万)附近,float的精度就等于1了,float果然难堪大用。

-------------Some Interesting Resule for Double--------------------
// 0.1d附近的double
Nearest smaller double:   0.09999999999999999167332731531132594682276248931884765625
Current double:           0.1000000000000000055511151231257827021181583404541015625
Nearest bigger double :   0.10000000000000001942890293094023945741355419158935546875

// 1.0d附近的double
Nearest smaller double:   0.99999999999999988897769753748434595763683319091796875
Current double:           1
Nearest bigger double :   1.0000000000000002220446049250313080847263336181640625

// 10.0d附近的double
Nearest smaller double:    9.9999999999999982236431605997495353221893310546875000
Current double:           10.00
Nearest bigger double :   10.0000000000000017763568394002504646778106689453125000

// 1e14d附近的double
Nearest smaller double:    99999999999999.9843750000000000000000000000000000000000000000000000
Current double:           100000000000000.00000000000000000000000000000000
Nearest bigger double :   100000000000000.0156250000000000000000000000000000000000000000000000

// 1e15d附近的double
Nearest smaller double:    999999999999999.8750000000000000000000000000000000000000000000000000
Current double:           1000000000000000.0000000000000000000000000000000000
Nearest bigger double :   1000000000000000.1250000000000000000000000000000000000000000000000000

// 1e16d附近的double
Nearest smaller double:    9999999999999998.0000000000000000000000000000000000000000000000000000
Current double:           10000000000000000.0000000000000000000000000000000000000
Nearest bigger double :   10000000000000002.0000000000000000000000000000000000000000000000000000

// 1e17d附近的double
Nearest smaller double:    99999999999999984.0000000000000000000000000000000000000000000000000000
Current double:           100000000000000000.000000000000000000000000000000000000000
Nearest bigger double :   100000000000000016.0000000000000000000000000000000000000000000000000000

// 1e304d附近的double
Nearest smaller double:    9999999999999998174371273630364736815867488735718786093662414371947263704524926751224722911637244940234972882804879769415602664816552507597839565690480126952738889402600333599657997758603312171995012866291845554976690497648524473448849371595248581587050582985041870802940253992811266476846330599148879872.0000000000000000000000000000000000000000000000000000
Current double:            9999999999999999392535525055364621860040287220117324953190771571323204563013233902843309257440507748436856118056162172578717193742636030530235798840866882774987301441682011041067710253162440905843719802548551599076639682550821832659549112269607949805346034918662572406407604380845959862074904348138143744.000000000000000000000000000000000000000000000000
Nearest bigger double :   10000000000000000610699776480364506904213085704515863812719128770699145421501541054461895603243770556638739353307444575741831722668719553462632031991253638597235713480763688482477422747721569639692426738805257643176588867453119191870248852943967318023641486852283274009874954768880653247303478097127407616.0000000000000000000000000000000000000000000000000000

-------------Some Interesting Resule for Float--------------------

// 0.1f附近的float
Nearest smaller float:    0.0999999940395355224609375
Current float:            0.100000001490116119384765625
Nearest bigger float:     0.10000000894069671630859375

// 1.0f附近的float
Nearest smaller float:    0.999999940395355224609375
Current float:            1
Nearest bigger float:     1.00000011920928955078125

// 10.0f附近的float
Nearest smaller float:     9.99999904632568359375000
Current float:            10.00
Nearest bigger float:     10.00000095367431640625000

// 1e5f附近的float
Nearest smaller float:     99999.99218750000000000000000
Current float:            100000.00000000000
Nearest bigger float:     100000.00781250000000000000000

// 1e6f附近的float
Nearest smaller float:     999999.93750000000000000000000
Current float:            1000000.0000000000000
Nearest bigger float:     1000000.06250000000000000000000

// 1e7f附近的float
Nearest smaller float:     9999999.00000000000000000000000
Current float:            10000000.0000000000000000
Nearest bigger float:     10000001.00000000000000000000000

// 1e8f附近的float
Nearest smaller float:     99999992.00000000000000000000000
Current float:            100000000.000000000000000000
Nearest bigger float:     100000008.00000000000000000000000

// 1e38f附近的float
Nearest smaller float:     99999986661652122824821048795547566080.00000000000000000000
Current float:             99999996802856924650656260769173209088.00000000000000000000000
Nearest bigger float:     100000006944061726476491472742798852096.0000000000000000000000

精确计算java中float和double的精度

时间: 2024-10-21 00:12:01

精确计算java中float和double的精度的相关文章

java控制float和double的精度

在做读取Excel表格数据时,碰到有小数点的数字,用double和float来求和时会多出好多位小数,看起来总觉得怪怪的,怎样控制它的长度呢? DecimalFormat df = new DecimalFormat("########.0"); //四舍五入 value = Double.parseDouble(df.format(value)); 我这里是控制一位小数,如果要求两位,就写成########.00 java控制float和double的精度,布布扣,bubuko.co

Java中float和double转换的问题

为什么double转float不会出现数据误差,而float转double却误差如此之大?   double d = 3.14; float f = (float)d; System.out.println(f); 输出结果是:3.14; float f = 127.1f; double d = f; System.out.println(d); 输出结果是:127.0999984741211 为什么结果会是这样呢? 如何避免这样的问题发生,让float转double能得到实际的数据? 解决办法

JAVA中float与double的区

float是单精度类型,精度是8位有效数字,取值范围是10的-38次方到10的38次方,float占用4个字节的存储空间 double是双精度类型,精度是17位有效数字,取值范围是10的-308次方到10的308次方,double占用8个字节的存储空间 当你不声明的时候,默认小数都用double来表示,所以如果要用float的话,则应该在其后加上f 例如:float a=1.3; 则会提示不能将double转化成float  这成为窄型转化 如果要用float来修饰的话,则应该使用float a

Java浮点数float和double精确计算的精度误差问题总结

1.float整数计算误差 案例:会员积分字段采用float类型,导致计算会员积分时,7位整数的数据计算结果出现误差. 原因:超出float精度范围,无法精确计算. float和double的精度是由尾数的位数来决定的.浮点数在内存中是按科学计数法来存储的,其整数部分始终是一个隐含着的“1”,由于它是不变的,故不能对精度造成影响. float:2^23 = 8388608,一共七位,这意味着最多能有7位有效数字,但绝对能保证的为6位,也即float的精度为6~7位有效数字: double:2^5

【转】JAVA程序中Float和Double精度丢失问题

原文网址:http://blog.sina.com.cn/s/blog_827d041701017ctm.html 问题提出:12.0f-11.9f=0.10000038,"减不尽"为什么? 来自MSDN的解释: http://msdn.microsoft.com/zh-cn/c151dt3s.aspx 为何浮点数可能丢失精度浮点十进制值通常没有完全相同的二进制表示形式. 这是 CPU 所采用的浮点数据表示形式的副作用.为此,可能会经历一些精度丢失,并且一些浮点运算可能会产生意外的结果

Java 浮点数 float或double类型的表示范围和精度

隐约记得,浮点数判断大小好像有陷阱,因为底层的二进制数不能精确表示所有的小数.有时候会产生让人觉得莫名其妙的事情. 如在java中, 0.99999999f==1f //true 0.9f==1f //false 要明白这些,首先要搞清楚float和double在内存结构 1.内存结构 float和double的范围是由指数的位数来决定的. float的指数位有8位,而double的指数位有11位,分布如下: float: 1bit(符号位) 8bits(指数位) 23bits(尾数位) dou

float、double的精度、范围,在内存中的存储方式

float.double的精度,在内存中的存储方式 ? 一.浮点型变量在内存中的存储方式 Java的浮点数遵循IEEE 754标准,采用二进制数据的科学计数法来表示浮点数,float遵从的是IEEE R32.24 ,而double 遵从的是R64.53.该标准中表示的浮点数表示分为规约形式和非规约形式以及特殊情况. ??? 无论是单精度还是双精度在存储中都分为三个部分: 符号位(Sign) : 0代表正,1代表为负 指数位(Exponent):用于存储科学计数法中的指数数据,并且采用移位存储 尾

Java中String转换Double类型 Java小数点后留两位

Java中String转换Double类型 double num1 = 0.0; String qq = "19.987"; num1 = Double.valueOf(qq.toString()); 太祖元年 Java小数点后留两位 double num1 =11; double num1 =21; String num1 =""; DecimalFormat df = new DecimalFormat(".00");num3 = df.fo

Java中的浮点型(Double&Float)计算问题

在刚刚做完的一个项目中,遇到了double型计算不精确的问题.到网上查找后,问题得到解决.经验共享,在这里总结一下. Java中的浮点数类型float和double不能够进行精确运算.这个问题有时候非常严重.比如,经过double型直接计算,1.4×1.5有时会得出2.0999999999999996的结果,但实际上,应该得到2.10.而且,类似的情况并不仅限于乘法计算. 在有的编程语言中提供了专门的货币类型来处理这种情况,但是Java没有.所以,在商业计算中我们要用:java.math.Big