JAVA中的浮点数与二进制


先来看一段简单的代码

public static void main(String[] args) {    
    System.out.println(0.1+0.2);
}

打印结果如下:

0.30000000000000004  //为什么0.1+0.2不等于0.3?

为什么会出现这种诡异的答案呢?

这还得从浮点数的二进制表示方法说起

这年头儿,连过马路的老奶奶估计都知道,计算机是采用二进制计数的



来,简单的考你一下:请把数字15写成二进制的形式

//答案应该比较简单0000 1111

相信你对整数的二进制已经比较熟悉


但如果我换成小数呢?3.14159265359该怎么表示?

其实,如果不搞底层设计,一般人还真的不太知道这个答案

但你只有理解小数在二进制中是如何表示的

才能够明白文章开头的案例【为什么0.1+0.2不等于0.3?】



我们以小数0.1为例,看看它是如何使用二进制存储的

第一步,把0.1 乘以 2, 得到的结果0.2,  整数部分 0 取走
第二步,把上一步留下的小数部分0.2,乘以2,得到的结果0.4,  整数部分 0 取走
第三步,把上一步留下的小数部分0.4,乘以2,得到的结果0.8,  整数部分 0 取走
第四步,把上一步留下的小数部分0.8,乘以2,得到的结果1.6,  整数部分 1 取走......直到,小数部分为0

下图展示了计算的过程 ↓


最终的二进制,就是整数部分的合集

写出来大概是这样:

0001 1001 1001 1001 1001 ...

可以看到,1001 的部分,是无限循环的

我们用二进制的小数把它写出来大概是这样

0.0001 1001 1001 1001 1001 ...

它相当于

你会发现,它并不等于0.1

它只是一个近似值

所以,二进制保留的位数越多,精度也就越高


早期的计算机其实是不能处理浮点数的

直到IEEE 754 标准出现后,计算机才能处理浮点数

根据IEEE 754 标准,float类型,共4个字节,32个bit位

其中指数部分占8位,小数部分占23位

那么 指数部分小数部分 分别用来保存什么呢?

我们依然以 数字 0.1 为例,我们刚才已经得到了它的二进制

0.0001 1001 1001 1001 1001 ...

按照IEEE 754标准,我们需要把它的小数点,向右移动

直到整数部分是1为止

0.0001 1001 1001 1001 1001 ...
//小数点向右移动4位
//相当于乘以2的4次方
0001.1001 1001 1001 1001 ...
//也就是
1.1001 1001 1001 1001 ...
//为了维持数字大小不变
//再乘以2的-4次方

最终变成

float小数部分只能保存23位

-4 就是 指数部分

1001......就是 小数部分

小数点的位置不是固定的,而是浮动的,故名:浮点数


了解到这一点,你就能够接受更多看起来奇怪而有趣的现象

比如

float f1=0.4f;
double d1=0.4;
System.out.println(f1==d1);//false
System.out.println(f1>d1); //true

f1还原为10进制,结果为0.40000000596046450000

d1还原为10进制,结果为0.40000000000000000000


关于二进制的底层,还有很多问题,有待我们探索

多了解一点,就少一些困惑



相关文章

Java 中的8种基本数据类型

Java 中有 8 种基本数据类型,分别为:6 种数字类型:4 种整数型:byte、short、int、long2 种浮点型:float、double1 种字符类型:char1 种布尔型:boolea...

java基本数据类型

前言前两节对java做了一个简单的介绍以及java环境的安装,那么本节就算是基本进入到java编程的正式学习,在进行学习java编程之前我首先要认识一下java里面有哪几种数据类型。四类八种Java的...

java float精度引发的问题

最近做地图相关的项目,因为使用float导致精度损失的问题回顾:根据百度地图api标注的经纬度返回类型为float,所以字段类型也定义为float// 百度地图api返回值 {"status":0,"...

Java程序员,一周Python入门:数据类型、变量、字符串和字符编码

Java程序员,一周Python入门:数据类型、变量、字符串和字符编码对比学习Java 和 Python 在数据类型、变量管理、字符串处理等方面有很大的区别,下面进行详细对比。1. 数据类型和变量1....

Java泛型全方位剖析:从入门到精通的完整指南(上篇)

Java泛型全方位剖析:从入门到精通的完整指南第一部分:引言与基础概念Java泛型是Java 5引入的重要特性,它允许类、接口和方法在定义时使用类型参数,提高了代码的类型安全性和可读性。本文将全面解析...