首页编程java编程java浮点数为什么不精确,java 浮点数为什么精度会丢失

java浮点数为什么不精确,java 浮点数为什么精度会丢失

编程之家2023-10-11109次浏览

大家好,今天小编来为大家解答以下的问题,关于java浮点数为什么不精确,java 浮点数为什么精度会丢失这个很多人还不知道,现在让我们一起来看看吧!

java浮点数为什么不精确,java 浮点数为什么精度会丢失

java中为什么两个浮点数相加结果不符合预期

我想你说的是java中的浮点数经过计算后,显示的结果是带有很多0的形式吧。这要从浮点数的概念讲起。在Java中float和double类型的数据,无法精确表示计算结果。这是由于float和double是不精确的计算。

例:

System.out.println(0.05+0.01);

java浮点数为什么不精确,java 浮点数为什么精度会丢失

System.out.println(1.0-0.42);

System.out.println(4.015*100);

System.out.println(123.3/100);

java浮点数为什么不精确,java 浮点数为什么精度会丢失

System.out.println(0.05);

得到如下结果:

0.060000000000000005

0.5800000000000001

401.49999999999994

1.2329999999999999

这是计算机从从本质上讲只能接收1和0,从二进制转为十进制浮点数时,是无论如何也没法精确保存的,因为浮点数实际上只是个近似值。在进行运算后,浮点数的精度就会进一步下降。

要保证精确计算,应使用BigDecimal类。例如

BigDecimal bd3=new BigDecimal(String.valueOf(0.05));

BigDecimal bd4=new BigDecimal(String.valueOf(0.01));

System.out.println((bd3.add(bd4)).doubleValue());

java 浮点数为什么精度会丢失

并不是java的浮点数精度会丢失,而是所有用二进制存储中的浮点数都可能会精度丢失(部分特殊的小数数值可以精确表示),所以计算机中存储的浮点数都存在精度丢失的风险,不过一边这个丢失的精度对我们正常的使用不会构成影响。

小数在转换为二进制时并不一定能用一个精确的二进制表示,大多数时候都是取的一个近似值,这就造成了精度的丢失。如果再用这个二进制进行计算,明显计算结果的精度会进一步丢失。

举个简单的例子把0.1用二进制表示(小数与二进制转换方法)

(1)0.1x2=0.2取整数位0得0.0

(2)0.2x2=0.4取整数位0得0.00

(3)0.4x2=0.8取整数位0得0.000

(4)0.8x2=1.6取整数位1得0.0001

(5)0.6x2=0.2取整数位1得0.00011

(6)0.2x2=0.4取整数位0得0.000110

(7)0.4x2=0.8取整数位0得0.0001100

(8)0.8x2=1.6取整数位1得0.00011001

(9)0.6x2=1.2取整数位1得0.000110011

(n)...

得到一个无限循环的二进制小数 0.000110011…,没办法用一个精确的二进制表示0.1。而且计算机中存储一个浮点数所用的位数也是有限的,所以只能选择在某一个精度进行保存。

当然也有特殊的小数,比如0.25的二进制为0.01

附:代码之谜(五)-浮点数(谁偷了你的精度?)

JavaScript为什么浮点数会丢失精度

JS浮点计算问题

问题

用js进行浮点数计算,结果可能会“超出预期”,大部分计算结果还是对的,但是我们可不想在计算这么严谨的事情上还有意外的惊喜。比如:

0.3+ 0.6= 0.8999999999999999

0.3- 0.2= 0.09999999999999998

0.3* 1.5= 0.44999999999999996

0.3/ 0.1= 2.9999999999999996

看完这几个计算结果,如果你没用过js,你可能会有点崩溃。我只能说,这就是js的魅力所在。

分析

在这之前,你需要知道以下几点:

js中数字类型只有Number;

js的Number是IEEE 754标准的64-bits的双精度数值

网上有很多关于此问题的解释,由于计算机是用二进制来存储和处理数字,不能精确表示浮点数,而js中没有相应的封装类来处理浮点数运算,直接计算会导致运算精度丢失。其实高级语言(c#,java)也存在此问题,只不过它们自己内部做了处理,把这种精度差异给屏蔽掉了。有些小数转换为二进制位数是无穷的(有循环),但是64位中小数最多只有52位,因此对于位数超过的相当于被截取了,导致了精度的丢失。这个地址可以用来浮点数和IEEE 754标准的64-bits的互转(背后是二进制的转换),用这个我们来验证下0.3-0.2。

0.3转换后为0.299999999999999988897769753748

0.2转换后为0.200000000000000011102230246252

0.299999999999999988897769753748-0.200000000000000011102230246252=0.099999999999999977795539507496

这和js直接计算的结果0.09999999999999998想吻合。

分析下来,终于明白并不是js自身发育不良,只是没有及时补充营养,我们只能另想出路了。

以上是网上找的

我以前遇到过问题2中浏览器计算的结果是两种,所以和浏览器也有问题

java float double精度为什么会丢失

由于对float或double的使用不当,可能会出现精度丢失的问题。问题大概情况可以通过如下代码理解:

publicclassFloatDoubleTest{

publicstaticvoidmain(String[]args){

floatf=20014999;

doubled=f;

doubled2=20014999;

System.out.println("f="+f);

System.out.println("d="+d);

System.out.println("d2="+d2);

}

}

得到的结果如下:

f=2.0015E7

d=2.0015E7

d2=2.0014999E7

从输出结果可以看出double可以正确的表示20014999,而float没有办法表示20014999,得到的只是一个近似值。这样的结果很让人讶异。20014999这么小的数字在float下没办法表示。于是带着这个问题,做了一次关于float和double学习,做个简单分享,希望有助于大家对java浮点数的理解。

关于java的float和double

Java语言支持两种基本的浮点类型:float和double。java的浮点类型都依据IEEE754标准。IEEE754定义了32位和64位双精度两种浮点二进制小数标准。

IEEE754用科学记数法以底数为2的小数来表示浮点数。32位浮点数用1位表示数字的符号,用8位来表示指数,用23位来表示尾数,即小数部分。作为有符号整数的指数可以有正负之分。小数部分用二进制(底数2)小数来表示。对于64位双精度浮点数,用1位表示数字的符号,用11位表示指数,52位表示尾数。如下两个图来表示:

float(32位):

double(64位):

都是分为三个部分:

(1)一个单独的符号位s直接编码符号s。

(2)k位的幂指数E,移码表示。

(3)n位的小数,原码表示。

那么20014999为什么用float没有办法正确表示?

结合float和double的表示方法,通过分析20014999的二进制表示就可以知道答案了。

以下程序可以得出20014999在double和float下的二进制表示方式。

publicclassFloatDoubleTest3{

publicstaticvoidmain(String[]args){

doubled=8;

longl=Double.doubleToLongBits(d);

System.out.println(Long.toBinaryString(l));

floatf=8;

inti=Float.floatToIntBits(f);

System.out.println(Integer.toBinaryString(i));

}

}

输出结果如下:

Double:100000101110011000101100111100101110000000000000000000000000000

Float:1001011100110001011001111001100

对于输出结果分析如下。对于都不double的二进制左边补上符号位0刚好可以得到64位的二进制数。根据double的表示法,分为符号数、幂指数和尾数三个部分如下:

对于float左边补上符号位0刚好可以得到32位的二进制数。根据float的表示法,也分为符号数、幂指数和尾数三个部分如下:

绿色部分是符号位,红色部分是幂指数,蓝色部分是尾数。

对比可以得出:符号位都是0,幂指数为移码表示,两者刚好也相等。唯一不同的是尾数。

在double的尾数为:0011000101100111100101110000000000000000000000000000,省略后面的零,至少需要24位才能正确表示。

而在float下面尾数为:00110001011001111001100,共23位。

为什么会这样?原因很明显,因为float尾数最多只能表示23位,所以24位的001100010110011110010111在float下面经过四舍五入变成了23位的00110001011001111001100。所以20014999在float下面变成了20015000。

也就是说20014999虽然是在float的表示范围之内,但在IEEE754的float表示法精度长度没有办法表示出20014999,而只能通过四舍五入得到一个近似值。

浮点运算很少是精确的,只要是超过精度能表示的范围就会产生误差。往往产生误差不是因为数的大小,而是因为数的精度。因此,产生的结果接近但不等于想要的结果。尤其在使用float和double作精确运算的时候要特别小心。

可以考虑采用一些替代方案来实现。如通过String结合BigDecimal或者通过使用long类型来转换。

关于java浮点数为什么不精确到此分享完毕,希望能帮助到您。

亚洲有哪些国家(亚洲有哪些国家以前是中国的)java为什么那么火 用途?Java为什么能火这么久