Java中浮点数运算不准确的原因及解决⽅案
问题
java中执⾏以下代码预期结果肯定是0.1
System.out.println(1.0-0.9);
但事实上运⾏结果为
原因
Java中的⼩数使⽤double和float表⽰,⼩数属于浮点型(默认为double)。
对于float型的值,则要在数字后加f或F,如12.3F,它在机器中占32位,4个字节来存储,表⽰精度较低。
double是64位。
那么⼀个⼩数在Java中是如何存储的呢?
Java语⾔中,float类型数字在计算机中的存储遵循IEEE-754格式标准:
(1)⼀个浮点数有3部分组成:符号位,指数部分e和底数部分m。
(2)浮点数需要⽤⼆进制来表⽰,所以底数m部分:使⽤⼆进制数来表⽰此浮点数的实际值。
(3)指数可正可负,所以,IEEE规定,此处算出的次⽅必须减去127才是真正的指数。因此指数部分有偏移量(float为127, double为1023)所以,float类型的指数可从-126到128。
(4)float类型符号位占1位,指数部分占⽤8bit(1个字节)的⼆进制数,可表⽰数值范围为0-255,尾数占23位(因为规格化表⽰,⼩数点左边的就是最⾼位⼀定为1,最⾼位省去不存储,在存储中占23bit,实际有24位精度)
(5)double类型符号位占1位,指数部分占11位,尾数占52位(因为规格化表⽰,⼩数点左边⼀定为1,所以实际有53位精度)
这样的表⽰⽅法⼀般都会失去⼀定的精确度,有些浮点数运算也会产⽣⼀定的误差。
解决⽅法
java中提供了BigDecimal类
public BigDecimal(double val)//将double表⽰形式转换为BigDecimal (不建议使⽤)
public BigDecimal(int val)//将int表⽰形式转换成BigDecimal
public BigDecimal(String val)//将String表⽰形式转换成BigDecimal
(1)⾸先调⽤public BigDecimal(String val)⽅法看看double型数在计算机中倒地是什么样的
BigDecimal one =new BigDecimal(1.0);
BigDecimal bigDecimal =new BigDecimal(0.9);
System.out.println(one);
System.out.println(bigDecimal);
以上代码的输出结果为
由于计算机⽆法准确的表⽰浮点数,所以我们的double型0.9对于计算机来说并不是,对于计算机来说它认为的0.1其实是
0.90000000000000002220446049250313080847263336181640625
此时再进⾏相减
System.out.println(one.subtract(bigDecimal));
System.out.println(1.0-0.9);
与直接相减的结果⼀致。
(2)所以这是调⽤另⼀个构造⽅法public BigDecimal(String val)bigdecimal格式化两位小数
String 构造⽅法是完全可预知的:写⼊ newBigDecimal(“0.9”) 将创建⼀个 BigDecimal,它正好等于预
期的 0.9。因此,通常建议优先使⽤String构造⽅法。当double必须⽤作BigDecimal的源时,使⽤String(double)转成String。
double a =1.0;
double b =0.9;
BigDecimal aDouble =new String(a));
BigDecimal bDouble =new String(b));
System.out.println(aDouble.subtract(bDouble));
另外有关BigDecimal除法格式化的舍⼊问题可以参考
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论