小数在内存中究竟是如何存储的(C语言代码详细讲解 3)

小数在内存中是如何存储的,揭秘诺贝尔奖级别的设计

IEEE 754 标准

  浮点数的存储以及加减乘除运算是一个比较复杂的问题,很多小的处理器在硬件指令方面甚至不支持浮点运算,其他的则需要一个独立的协处理器来处理这种运算,只有最复杂的处理器才会在硬件指令集中支持浮点运算。省略浮点运算,可以将处理器的复杂度减半!如果硬件不支持浮点运算,那么只能通过软件来实现,代价就是需要容忍不良的性能。

PC 和智能手机上的处理器就是最复杂的处理器了,它们都能很好地支持浮点运算。

  在六七十年代,计算机界对浮点数的处理比较混乱,各家厂商都有自己的一套规则,缺少统一的业界标准,这给数据交换、计算机协同工作带来了很大不便。

  作为处理器行业的老大,Intel 早就意识到了这个问题,并打算一统浮点数的世界。Intel 在研发 8087 浮点数协处理器时,聘请到加州大学伯克利分校的 William Kahan 教授(最优秀的数值分析专家之一)以及他的两个伙伴,来为 8087 协处理器设计浮点数格式,他们的工作完成地如此出色,设计的浮点数格式具有足够的合理性和先进性,被 IEEE 组织采用为浮点数的业界标准,并于 1985 年正式发布,这就是 IEEE 754 标准,它等同于国际标准 ISO/IEC/IEEE 60559。

IEEE 是 Institute of Electrical and Electronics Engineers 的简写,中文意思是“电气和电子工程师协会”。

  IEEE 754 简直是天才一般的设计,William Kahan 教授也因此获得了 1987 年的图灵奖。图灵奖是计算机界的“诺贝尔奖”。

  目前,几乎所有的计算机都支持 IEEE 754 标准,大大改善了科学应用程序的可移植性,C语言编译器在实现浮点数时也采用了该标准。

  不过,IEEE 754 标准的出现晚于C语言标准(最早的 ANSI C 标准于 1983 年发布),C语言标准并没有强制编译器采用 IEEE 754 格式,只是说要使用科学计数法的形式来表示浮点数,但是编译器在实现浮点数时,都采用了 IEEE 754 格式,这既符合C语言标准,又符合 IEEE 标准,何乐而不为。

特殊值

  IEEE 754 标准规定,当指数 exp 的所有位都为 1 时,不再作为“正常”的浮点数对待,而是作为特殊值处理:

1.	如果此时尾数 mant 的二进制位都为 0,则表示无穷大:
2.	如果符号 sign 为 1,则表示负无穷大;
3.	如果符号 sign 为 0,则表示正无穷大。
4.	如果此时尾数 mant 的二进制位不全为 0,则表示 NaN(Not a Number),也即这是一个无效的数字,或者该数字未经初始化。

非规格化浮点数

  当指数 exp 的所有二进制位都为 0 时,情况也比较特殊。

  对于“正常”的浮点数,尾数 mant 隐含的整数部分为 1,并且在读取浮点数时,内存中的指数 exp 要减去中间值 median 才能还原真实的指数 exponent,也即:

mantissa = 1.mant
exponent = exp - median

  但是当指数 exp 的所有二进制位都为 0 时,一切都变了!尾数 mant 隐含的整数部分变成了 0,并且用 1 减去中间值 median 才能还原真实的指数 exponent,也即:

mantissa = 0.mant
exponent = 1 - median

  对于 float,exponent = 1 - 127 = -126,指数 exponent 的值恒为 -126;对于 double,exponent = 1 - 1023 = -1022,指数 exponent 的值恒为 -1022。

  当指数 exp 的所有二进制位都是 0 时,我们将这样的浮点数称为“非规格化浮点数”;当指数 exp 的所有二进制位既不全为 0 也不全为 1 时,我们称之为“规格化浮点数”;当指数 exp 的所有二进制位都是 1 时,作为特殊值对待。 也就是说,究竟是规格化浮点数,还是非规格化浮点数,还是特殊值,完全看指数 exp。

+0 和 -0 的表示

对于非规格化浮点数,当尾数 mant 的所有二进制位都为 0 时,整个浮点数的值就为 0:

1.	如果符号 sign 为 0,则表示 +0;
2.	如果符号 sign 为 1,则表示 -0。

猜你喜欢

转载自blog.csdn.net/qq_43515862/article/details/108799001