微信搜索关注“水滴银弹”微信官方账号,第一时间获取优质技术干货。7年资深后端研发,用简单的方式把技术讲解清楚。

在上一篇文章中,我们主要介绍了在计算机中用不动点来表示数字的方法。

简单回顾一下,简单来说,当一个数用一个定数表示时,大家一致认为小数点的位置是固定的,整数部分和小数部分分别转换为二进制,这是定数的结果。

但是用定点来表示小数时,存在数值范围和精度范围有限的缺点,所以在计算机中,我们一般用浮点数来表示小数。

在本文中,让我们详细了解浮点数是如何表示小数的,以及浮点数的范围和精度。

什么是浮点数?

首先,我们需要了解什么是浮点数?

我们之前学过定点数,其中“定点数”是指固定的小数点位置。浮点数的“浮点”是指小数点的位置可以浮动。

你怎么理解这个?

其实浮点数是用科学的计数方法表示的,比如十进制的十进制8.345,可以用科学的计数方法多种方式表示:

8.345=8.345*10^0

8.345=83.45*10^-1

8.345=834.5*10^-2

.

看到了吗?用这种科学的计数方法表示小数时,小数点的位置就变成了“浮点”,这就是浮点名称相对于定点的由来。

用同样的规则,对于二进制数,我们也可以用科学记数法,也就是我们可以把基数10改成2。

00-1010我们已经知道浮点数是用科学计数来表示一个数的,它的格式可以写成:

V=(-1)^S*M*R^E

每个变量的含义如下:

s:符号位,取值为0或1,决定一个数字的符号,0表示正,1表示负M:尾数,用小数表示。比如8.345 * 10 0,8.345是尾数R:基数,表示十进制数R是10,二进制数R是2E:指数,用整数表示,比如10。

现在假设我们用32位来表示一个浮点数,并按照一定的规则用上面的变量填充这些位:

什么是浮点型(浮点数怎么定义)-冯金伟博客园

假设我们定义以下规则来填充这些位:

符号S占1位,指数E占10位,尾数M占21位。根据这个规则,十进制数25.125被转换成浮点数。转换过程是这样的(D代表十进制,B代表二进制):

部分:25(D)=11001(B)小数部分:0.125(D)=0.001(B)用二进制科学符号表示:25.125(D)=11001.001(B)=1.1001001 * 2 4(B)

根据上面定义的规则,将它填充到32位,就是这样:

什么是浮点型(浮点数怎么定义)-冯金伟博客园

浮点数的结果出来了,不是很简单吗?

但这里有个问题。我们刚才定义的规则,符号位S占1位,指数位E占10位,尾数位M占21位,是随便拍脑袋定义的。

如果你也想做一个新的规则,比如符号位s占1位,指数位e这次占5位,尾数m占25位,可以吗?当然可以。

根据这个规则,浮点数是这样的:

什么是浮点型(浮点数怎么定义)-冯金伟博客园

我们可以看到,指数和尾数分配的位数是不同的,这将导致以下情况:

指数位越多,尾数位越少,表达式的范围越大,但精度越差。相反,指数位越少,尾数位越多,表达式的范围越小,但浮点数格式的精度越好。由于定义规则的不同,会得到不同的结果,表达的范围和精度也不同。早期人们提出浮点数的定义就是这种情况。当时,有许多计算机制造商,如IBM。

这样一来,当一个程序在不同厂家的计算机中进行浮点运算时,需要转换成这个厂家指定的浮点格式才能进行计算,这必然会增加计算的成本。

那如何解决这个问题呢?业界迫切需要一个统一的浮点标准。

p>

浮点数标准

直到1985年,IEEE 组织推出了浮点数标准,就是我们经常听到的 IEEE754 浮点数标准,这个标准统一了浮点数的表示形式,并提供了 2 种浮点格式:

单精度浮点数 float:32 位,符号位 S 占 1 bit,指数 E 占 8 bit,尾数 M 占 23 bit双精度浮点数 float:64 位,符号位 S 占 1 bit,指数 E 占 11 bit,尾数 M 占 52 bit

为了使其表示的数字范围、精度最大化,浮点数标准还对指数和尾数进行了规定:

尾数 M 的第一位总是 1(因为 1 <= M < 2),因此这个 1 可以省略不写,它是个隐藏位,这样单精度 23 位尾数可以表示了 24 位有效数字,双精度 52 位尾数可以表示 53 位有效数字指数 E 是个无符号整数,表示 float 时,一共占 8 bit,所以它的取值范围为 0 ~ 255。但因为指数可以是负的,所以规定在存入 E 时在它原本的值加上一个中间数 127,这样 E 的取值范围为 -127 ~ 128。表示 double 时,一共占 11 bit,存入 E 时加上中间数 1023,这样取值范围为 -1023 ~ 1024。

除了规定尾数和指数位,还做了以下规定:

指数 E 非全 0 且非全 1:规格化数字,按上面的规则正常计算指数 E 全 0,尾数非 0:非规格化数,尾数隐藏位不再是 1,而是 0(M = 0.xxxxx),这样可以表示 0 和很小的数指数 E 全 1,尾数全 0:正无穷大/负无穷大(正负取决于 S 符号位)指数 E 全 1,尾数非 0:NaN(Not a Number)什么是浮点型(浮点数怎么定义)-冯金伟博客园

标准浮点数的表示

有了这个统一的浮点数标准,我们再把 25.125 转换为标准的 float 浮点数:

整数部分:25(D) = 11001(B)小数部分:0.125(D) = 0.001(B)用二进制科学计数法表示:25.125(D) = 11001.001(B) = 1.1001001 * 2^4(B)

所以 S = 0,尾数 M = 1.001001 = 001001(去掉1,隐藏位),指数 E = 4 + 127(中间数) = 135(D) = 10000111(B)。填充到 32 bit 中,如下:

什么是浮点型(浮点数怎么定义)-冯金伟博客园

这就是标准 32 位浮点数的结果。

如果用 double 表示,和这个规则类似,指数位 E 用 11 bit 填充,尾数位 M 用 52 bit 填充即可。

浮点数为什么有精度损失?

我们再来看一下,平时经常听到的浮点数会有精度损失的情况是怎么回事?

如果我们现在想用浮点数表示 0.2,它的结果会是多少呢?

0.2 转换为二进制数的过程为,不断乘以 2,直到不存在小数为止,在这个计算过程中,得到的整数部分从上到下排列就是二进制的结果。

0.2 * 2 = 0.4 -> 0
0.4 * 2 = 0.8 -> 0
0.8 * 2 = 1.6 -> 1
0.6 * 2 = 1.2 -> 1
0.2 * 2 = 0.4 -> 0(发生循环)

所以 0.2(D) = 0.00110…(B)。

因为十进制的 0.2 无法精确转换成二进制小数,而计算机在表示一个数字时,宽度是有限的,无限循环的小数存储在计算机时,只能被截断,所以就会导致小数精度发生损失的情况。

浮点数的范围和精度有多大?

最后,我们再来看一下,用浮点数表示一个数字,其范围和精度能有多大?

以单精度浮点数 float 为例,它能表示的最大二进制数为 +1.1.11111…1 * 2^127(小数点后23个1),而二进制 1.11111…1 ≈ 2,所以 float 能表示的最大数为 2^128 = 3.4 * 10^38,即 float 的表示范围为:-3.4 * 10^38 ~ 3.4 * 10 ^38。

它能表示的精度有多小呢?

float 能表示的最小二进制数为 0.0000….1(小数点后22个0,1个1),用十进制数表示就是 1/2^23。

用同样的方法可以算出,double 能表示的最大二进制数为 +1.111…111(小数点后52个1) * 2^1023 ≈ 2^1024 = 1.79 * 10^308,所以 double 能表示范围为:-1.79 * 10^308 ~ +1.79 * 10^308。

double 的最小精度为:0.0000…1(51个0,1个1),用十进制表示就是 1/2^52。

从这里可以看出,虽然浮点数的范围和精度也有限,但其范围和精度都已非常之大,所以在计算机中,对于小数的表示我们通常会使用浮点数来存储。

总结

这篇文章我们主要讲了数字的浮点数表示方式,总结如下:

浮点数一般用科学计数法表示把科学计数法中的变量,填充到固定 bit 中,即是浮点数的结果在浮点数提出的早期,各个计算机厂商各自制定自己的浮点数规则,导致不同厂商对于同一个数字的浮点数表示各不相同,在计算时还需要先进行转换才能进行计算后来 IEEE 组织提出了浮点数的标准,统一了浮点数的格式,并规定了单精度浮点数 float 和双精度浮点数 double,从此以后各个计算机厂商统一了浮点数的格式,一直延续至今浮点数在表示小数时,由于十进制小数在转换为二进制时,存在无法精确转换的情况,而在固定 bit 的计算机中存储时会被截断,所以浮点数表示小数可能存在精度损失浮点数在表示一个数字时,其范围和精度非常大,所以我们平时使用的小数,在计算机中通常用浮点数来存储

微信搜索关注「水滴与银弹」公众号,第一时间获取优质技术干货。7年资深后端研发,用简单的方式把技术讲清楚。

快三大小单双稳赚买法img.com/origin/pgc-image/858c980c67a14fd3a6be282e1f7a2ef1?from=pc”>

这就是标准 32 位浮点数的结果。

如果用 double 表示,和这个规则类似,指数位 E 用 11 bit 填充,尾数位 M 用 52 bit 填充即可。

浮点数为什么有精度损失?

我们再来看一下,平时经常听到的浮点数会有精度损失的情况是怎么回事?

如果我们现在想用浮点数表示 0.2,它的结果会是多少呢?

0.2 转换为二进制数的过程为,不断乘以 2,直到不存在小数为止,在这个计算过程中,得到的整数部分从上到下排列就是二进制的结果。

0.2 * 2 = 0.4 -> 0
0.4 * 2 = 0.8 -> 0
0.8 * 2 = 1.6 -> 1
0.6 * 2 = 1.2 -> 1
0.2 * 2 = 0.4 -> 0(发生循环)

所以 0.2(D) = 0.00110…(B)。

因为十进制的 0.2 无法精确转换成二进制小数,而计算机在表示一个数字时,宽度是有限的,无限循环的小数存储在计算机时,只能被截断,所以就会导致小数精度发生损失的情况。

浮点数的范围和精度有多大?

最后,我们再来看一下,用浮点数表示一个数字,其范围和精度能有多大?

以单精度浮点数 float 为例,它能表示的最大二进制数为 +1.1.11111…1 * 2^127(小数点后23个1),而二进制 1.11111…1 ≈ 2,所以 float 能表示的最大数为 2^128 = 3.4 * 10^38,即 float 的表示范围为:-3.4 * 10^38 ~ 3.4 * 10 ^38。

它能表示的精度有多小呢?

float 能表示的最小二进制数为 0.0000….1(小数点后22个0,1个1),用十进制数表示就是 1/2^23。

用同样的方法可以算出,double 能表示的最大二进制数为 +1.111…111(小数点后52个1) * 2^1023 ≈ 2^1024 = 1.79 * 10^308,所以 double 能表示范围为:-1.79 * 10^308 ~ +1.79 * 10^308。

double 的最小精度为:0.0000…1(51个0,1个1),用十进制表示就是 1/2^52。

从这里可以看出,虽然浮点数的范围和精度也有限,但其范围和精度都已非常之大,所以在计算机中,对于小数的表示我们通常会使用浮点数来存储。

总结

这篇文章我们主要讲了数字的浮点数表示方式,总结如下:

浮点数一般用科学计数法表示把科学计数法中的变量,填充到固定 bit 中,即是浮点数的结果在浮点数提出的早期,各个计算机厂商各自制定自己的浮点数规则,导致不同厂商对于同一个数字的浮点数表示各不相同,在计算时还需要先进行转换才能进行计算后来 IEEE 组织提出了浮点数的标准,统一了浮点数的格式,并规定了单精度浮点数 float 和双精度浮点数 double,从此以后各个计算机厂商统一了浮点数的格式,一直延续至今浮点数在表示小数时,由于十进制小数在转换为二进制时,存在无法精确转换的情况,而在固定 bit 的计算机中存储时会被截断,所以浮点数表示小数可能存在精度损失浮点数在表示一个数字时,其范围和精度非常大,所以我们平时使用的小数,在计算机中通常用浮点数来存储

微信搜索关注「水滴与银弹」公众号,第一时间获取优质技术干货。7年资深后端研发,用简单的方式把技术讲清楚。