【Java处理小数运算】0.1024-0.1等于多少

本文探讨了1024程序员节期间关于0.1024二进制转换的精度问题,解释了浮点数表示小数时的精度损失,并介绍了如何使用Java的BigDecimal进行精确计算。通过实例演示了浮点数运算的局限和BigDecimal的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

谨以此篇献给辛勤工作(moyu)的1024。

在这里插入图片描述

0.1024问题

又到了,一年一度的1024程序员佳节,众所周知1024的二进制是,等一下让程序跑一会…

System.out.println(new BigInteger("1024", 10).toString(2));

对,是10000000000。那么0.1024的二进制是多少呢?

System.out.println(1024 - 1);
System.out.println(0.1024 -0.1);
System.out.println(0.9 - 0.8);

以上三个输出结果是多少呢?

1023 当然是1023啦,小傻瓜
0.0023999999999999994
0.09999999999999998

好了,老程序员请不要疑惑,新入坑的1024们请张大你的嘴巴。
在这里插入图片描述

原因

运算过程中计算机会用浮点数表示小数,导致精度丢失出现以上问题。

浮点数是计算机用来表示小数的一种数据类型,采用科学计数法。

在Java中,double是双精度,64位,浮点数,默认是0.0d。float是单精度,32位,浮点数,默认是0.0f;

32位单精度二进制 = [1个符号位] [8个阶码位] [23个尾数位]
64位单精度二进制 = [1个符号位] [11个阶码位] [52个尾数位]
小数 = [正负符号位]  [整数部分] . [小数部分]

小数转换成二进制

十进制0.9 = 二进制1100 1100 1100 1100 1100 1100 其中1100循环
  计算过程:  0.9 x 2 = 1.8取整得1 取上次结果的小数部分乘以2
                  0.8 x 2 = 1.6取整得11.6的小数部分即0.6乘以2

                  0.6 x 2 = 1.2取整得11.2的小数部分即0.2乘以2

                  0.2 x 2 = 0.4取整得00.4的小数部分0.4乘以2

                  0.4 x 2 = 0.8取整得0  取上次结果的小数部分乘以2

                  0.8 x 2 = 1.6取整得1

                  0.6 x 2 = 1.2取整得1

                           ...循环

当到达一定值自动开始使用科学计数法,并保留相关精度的有效数字,所以结果是个近似数,并且指数为整数。在十进制中小数有些是无法完整用二进制表示的。所以只能用有限位来表示,从而在存储时可能就会有误差。
在这里插入图片描述

解决

Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。

float和double只能用来做科学计算或者是工程计算,在商业计算中要用java.math.BigDecimal。
BigDecimal所创建的是对象,必须调用其相对应的方法才能进行数学运算。方法中的参数也必须是BigDecimal的对象。

示例:

BigDecimal bigDecimal1 = new BigDecimal("0.1024");
BigDecimal bigDecimal2 = new BigDecimal("0.1");
//0.1024 - 0.1
System.out.println(bigDecimal1.subtract(bigDecimal2));
//保留小数X位
System.out.println(bigDecimal1.setScale(2, BigDecimal.ROUND_DOWN));

结果:

0.0024
0.10

注:BigDecimal(double) 不推荐使用

BigDecimal bigDecimal1 = new BigDecimal(0.1024);
BigDecimal bigDecimal2 = new BigDecimal(0.1);
//0.1024 - 0.1
System.out.println(bigDecimal1.subtract(bigDecimal2));

结果:

0.00239999999999999935607064571740920655429363250732421875

在这里插入图片描述
源码中也提到此构造函数的结果可能有些不可预测。可以使用String构造函数是完全可预测的。

舍入模式

ROUND_UP       		//向远离0的方向舍入
ROUND_DOWN     		//向零方向舍入
ROUND_CEILING  		//向正无穷方向舍入
ROUND_FLOOR    		//向负无穷方向舍入
ROUND_HALF_UP    	//四舍五入
ROUND_HALF_DOWN    //向最近的一边舍入,如果两边(的距离)是相等,向下舍入, 例如1.85 保留一位小数结果为1.8
ROUND_HALF_EVEN    //向最近的一边舍入,如果两边是相等,保留位数是奇数,使用ROUND_HALF_UP,偶数,使用ROUND_HALF_DOWN
ROUND_UNNECESSARY  //计算结果是精确的,不需要舍入模式

在这里插入图片描述

点赞 收藏 关注
据说,世上只有两种人:一种是懂二进制的,一种是不懂二进制。

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三省同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值