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


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

    在这里插入图片描述

    0.1024问题

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

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

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

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

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

    1023 当然是1023啦,小傻瓜
    0.0023999999999999994
    0.09999999999999998
    
    • 1
    • 2
    • 3

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

    原因

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

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

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

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

    小数转换成二进制

    十进制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
    
                               ...循环
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

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

    解决

    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));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    结果:

    0.0024
    0.10
    
    • 1
    • 2

    注:BigDecimal(double) 不推荐使用

    BigDecimal bigDecimal1 = new BigDecimal(0.1024);
    BigDecimal bigDecimal2 = new BigDecimal(0.1);
    //0.1024 - 0.1
    System.out.println(bigDecimal1.subtract(bigDecimal2));
    
    • 1
    • 2
    • 3
    • 4

    结果:

    0.00239999999999999935607064571740920655429363250732421875
    
    • 1

    在这里插入图片描述
    源码中也提到此构造函数的结果可能有些不可预测。可以使用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  //计算结果是精确的,不需要舍入模式
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

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

  • 相关阅读:
    python│蓝桥杯省赛真题星期一问题
    leetcode - 2938. Separate Black and White Balls
    Mybatis中 collection 和 association 标签 的区别
    公众号免费注册教程
    前端--性能优化【中篇】--html+css优化与图片优化
    Burpsuite专业版安装步骤
    uniapp的微信小程序授权头像昵称(最新版)
    react-starter脚手架搭建过程
    Spark SQL简介
    国内外AI programmer 大全集--持续更新
  • 原文地址:https://blog.csdn.net/qq_35764295/article/details/127445945