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

本文详细介绍了Java中float和double类型的精度误差问题,以及如何使用BigDecimal进行精确计算。通过多个案例分析了浮点数在整数、小数计算时可能出现的误差,探讨了浮点数和定点数的区别。此外,还提供了BigDecimal的构造方法选择建议,以及一个简化BigDecimal运算的工具类Arith,包含加减乘除和四舍五入的方法。
摘要由CSDN通过智能技术生成

1、float整数计算误差

案例:会员积分字段采用float类型,导致计算会员积分时,7位整数的数据计算结果出现误差。

原因:超出float精度范围,无法精确计算。

float和double的精度是由尾数的位数来决定的。浮点数在内存中是按科学计数法来存储的,其整数部分始终是一个隐含着的“1”,由于它是不变的,故不能对精度造成影响。

float:2^23 = 8388608,一共七位,这意味着最多能有7位有效数字,但绝对能保证的为6位,也即float的精度为6~7位有效数字;

double:2^52 = 4503599627370496,一共16位,同理,double的精度为15~16位。

难道只是位数多大的问题,字段类型换成double就可以解决吗?对于本案例是这样,因为都是整数计算,但如果有小数位,就不一定了,见下面案例。

2、double小数转bigdecimal后四舍五入计算有误差

案例:

double g= 12.35;

BigDecimal bigG=new BigDecimal(g).setScale(1, BigDecimal.ROUND_HALF_UP); //期望得到12.4

System.out.println("test G:"+bigG.doubleValue());

test G:12.3

原因:

定义double g= 12.35;  而在计算机中二进制表示可能这是样:定义了一个g=12.34444444444444449,

new BigDecimal(g)   g还是12.34444444444444449

new BigDecimal(g).setScale(1, BigDecimal.ROUND_HALF_UP); 得到12.3

正确的定义方式是使用字符串构造函数:

new BigDecimal("12.35").setScale(1, BigDecimal.ROUND_HALF_UP)

3、float和double做四则运算误差

案例:

public class Test{

public static void main(String args[]){

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);

}

}

结果:

0.060000000000000005

0.5800000000000001

401.49999999999994

1.2329999999999999

原因:

那么为什么会出现精度丢失呢?在查阅了一些资料以后,我稍微有了一些头绪,下面是本人的愚见,仅供参考。

首先得从计算机本身去讨论这个问题。我们知道,计算机并不能识别除了二进制数据以外的任何数据。无论我们使用何种编程语言,在何种编译环境下工作,都要先

把源程序翻译成二进制的机器码后才能被计算机识别。以上面提到的情况为例,我们源程序里的2.4是十进制的,计算机不能直接识别,要先编译成二进制。但问 题来了,2.4的二进制表示并非是精确的2.4,反而最为接近的二进制表示是2.3999999999999999。原因在于浮点数由两部分组成:指数和尾数,这点如果知道怎样进行浮点数的二进制与十进制转换,应该是不难理解的。如果在这个转换的过程中,浮点数参与了计算,那么转换的过程就会变得不可预

知,并且变得不可逆。我们有理由相信,就是在这个过程中,发生了精度的丢失。而至于为什么有些浮点计算会得到准确的结果,应该也是碰巧那个计算的二进制与 十进制之间能够准确转换。而当输出单个浮点型数据的时候,可以正确输出,如

double d = 2.4;

System.out.println(d);

输出的是2.4,而不是2.3999999999999999。也就是说,不进行浮点计算的时候,在十进制里浮点数能正确显示。这更印证了我以上

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值