本节书摘来自华章计算机《C语言编程魔法书:基于C11标准》一书中的第2章,第2.3节,作者 陈轶,更多章节内容可以访问云栖社区“华章计算机”公众号查看。
2.3 浮点数在计算机中的表示
当前主流处理器一般都能支持32位的单精度浮点数与64位的双精度浮点数的表示和计算,并且能遵循IEEE754-1985工业标准。现在此标准最新的版本是2008,其中增加了对16位半精度浮点数以及128位四精度浮点数的描述。C语言标准引入了一个浮点模型,可用来表达任意精度的浮点数,尽管当前主流C语言编译器尚未很好地支持半精度浮点数与四精度浮点数的表示和计算。关于C语言标准对浮点数的描述,我们稍后将在5.2节做更详细的介绍。
为了更好地理解IEEE754-1985中规格化(normalized)浮点数的表示法,我们先来介绍一下浮点数用一般二进制数的表示方法。一个浮点数包含了整数部分和尾数(即小数)部分。整数部分的表示与我们之前所讨论过的一样,第n位就表示2n,n从0开始计。而尾数部分则是第m位表示2-m,m从1开始计。对于一个0101.1010的二进制浮点数对应十进制数的计算如图2-7所示:
图2-7中,整i位即表示第i位整数;尾i位即表示第i位尾数。其中,第3位整数为最高位整数;第4位尾数表示最低位尾数。对二进制浮点数的表示有了概念之后,我们就可以看IEEE754-1985标准中对规格化浮点数的描述了。IEEE754-1985对32位单精度与64位双精度两种精度的浮点数进行描述。32位单精度浮点可表示的数值范围在±1.18×10-38到±3.4×1038,大约含有7位十进制有效数;64位双精度浮点可表示的数值范围在±2.23×10-308到±1.80×10308,大约含有15位十进制有效数。我们看到IEEE定义的浮点数的绝对值范围可以是一个远大于1的数,也可以是一个大于零但远小于1的数,即它的小数精度是可浮动的,所以称之为浮点数。如果说是定点数的话,它也可表示一个小数,但是其整数位数与小数位数的精度都是固定的。比如一个16.16的定点数表示整数部分采用16个比特,尾数部分也采用16个比特。而对于一个32位浮点数来说,既能使用16.16的格式,也能使用30.2的格式(即30个比特表示整数,2个比特表示尾数)或其他各种形式。而IEEE754-1985对规格化单精度浮点数的格式如下定义:
1)1位符号位,一般是最高位(31位),表示正负号。0表示正数,1表示负数。
2)8位指数位,又称阶码,位于23到30位。(阶码的计算后面会详细介绍。)
3)23位尾数,位于0到22位。
我们下面举一个实际的例子来详细说明一个十进制小数5.625如何表示成IEEE754标准的规格化32位单精度浮点数。
1)5.625是一个正数,所以符号位为0,即第31位为0。
2)我们将5.625依照图2-7那样写成一般小数的表示法——0101.101。
3)我们将此二进制浮点数用科学计数法来表示,使得二进制整数位为最高位的1。这里最高位为1的比特是从左往右数是第二个比特,所以将小数点就放到该比特的后面,得到1.01101×22。二进制数的科学记数法,底数的值显然就是2。
4)此时,我们能看到尾数部分是小数点后面的那串二进制数,即01101,而指数为2。现在我们来求阶码。阶码用的是中经指数偏差(exponent bias)处理后的指数,即用上述得到的指数加上偏差值所求得的和。IEEE754在单精度浮点中规定,偏差值为127。所以本例中,阶码部分为2+127=129,用二进制数表示就是1000 0001。
5)尾数部分从大到小照抄,低位的用0填充即可,所以这里的尾数部分二进制数为:011 0100 0000 0000 0000 0000。
6)将整个处理完的二进制数串起来获得:0(符号位)1000 0001(阶码)011 0100 0000 0000 0000 0000(尾数),用十六进制数表达就是:40B4 0000。
十进制小数转64位双精度浮点数的方法与上述雷同,只不过阶码用11位比特来表示,尾数则用52位比特表示,而偏差值则规定为1023。