C++中使用的浮点数包括采用的是IEEE标准下的浮点数表示方法。咱们知道在数学中能够将任何十进制的数写成以10为底的科学计数法的形式,以下html
其中显而易见,由于若是a比10大或者比1小都可以再次写成10的指数的形式,如ui
然而要想在二进制的世界中将数字写成以10为底的科学计数法的形式,着实有点麻烦,由于你首先须要将二进制的数先化成10进制的表示方法,而后才能写成科学计数法的形式。可是若是咱们稍微变通一下科学计数法的标记方法,问题就变得特别的简单了。之因此数学上使用的科学计数法选用10为底,是由于咱们一般使用的计数方式是十进制的。在计算机的世界中咱们使用的数倒是二进制的,因此咱们在这个世界中应该改用以2为底的科学计数法而不是10为底的科学计数法。此时咱们使用的科学计数法就表示成了以下形式,spa
对于一个二进制的数来讲是不言而喻的,以
为例.net
IEEE标准下的浮点数存储包括三个基本的组成:符号位、指数、尾数(the sign, the exponent, the mantissa),尾数是由小数部分和一个隐含的前导数位组成。至于前导数位隐含的缘由很简单(下面将会解释)。code
下面的表格展现了计算机存储单精度和双精度浮点数的层次结构,包括每一部分的比特位(比特范围用方括号括出,00表示最低位)htm
Sign | Exponent | Fraction | |
Single Precision | 1 [31] | 8 [30-23] | 23 [22-00] |
Double Precision | 1 [63] | 11 [62-52] | 52 [51-00] |
符号位很是简单,位于存储浮点数的最高比特位,且只占1比特。0表示正数,1表示负数。经过改变该比特位的值能够改变该浮点数的符号。blog
由于指数位既须要可以表示正指数也须要可以表示负指数,为了可以作到这一点,须要将真实的指数数值加上一个偏移值得到用来存储的指数值。对于IEEE标准下的单精度浮点数,这个偏移值是127。所以当真实的指数为0的时候,咱们存储的指数位为127。若是存储的指数值是200,那么真实的指数值就应该是(200-127),即73。后面的缘由会指出,指数为-127(指数位全为0)和+128(指数位全为1)会被用来存储特殊的数值。ip
对于双精度的浮点数,指数位的长度位11比特,偏移量位1023。内存
尾数也被称为有效数位(significand),决定浮点数的精确度。它由隐含的前导数位(小数点左边的部分)和小数部分(小数点右边的部分)组成,由于咱们采用以2为底的科学计数法表示二进制数,那么小数点左边的尾数部分天然是固定值1(),因此前导数位咱们不须要明确的表示出来,咱们只须要存储尾数的小数部分就能够了。ci
下面就以单精度浮点数来浮点数的存储策略。
十进制数0.1562510 写成二进制的形式为0.001012。经过乘以以2为底的指数,将小数点向右移动3位后获得
这个时候咱们就可以肯定它的尾数的小数部分和指数分别是多少了,尾数的小数部分位.012,指数为-3。具体存储方法见下图,
在IEEE 745标准下,咱们用三部分来表示一个浮点数:
咱们先来考虑单精度浮点数的范围问题。注意到咱们用来存储双精度浮点数的是一块长为32bits的内存,咱们从新解释了一下该快内存中数字的存储规则使得表示数的范围大大增长。可是咱们看看这样子带来了什么问题?
对于32bits的无符号整数来讲,它能够表示0~232-1范围内的任意整数。可是单精度的浮点数却作不到这一点,由于浮点数的存储策略中用来存储尾数的长度只有24bits,这个时候单精度浮点数就会把将底位的部分截断,例如
11110000 11001100 10101010 10101111 // 32-bit integer = +1.1110000 11001100 10101011 x 2^31 // Single-Precision Float = 11110000 11001100 10101011 00000000 // Corresponding Value
这样的方法能够近似32bits的值,可是并不能获得准确的结果。忽略精确度的问题,浮点数可以表示的范围是2127,而32bits整数的表示范围是232。
按照上面的浮点数表示方法,咱们发现并不能表示出数值0的大小。由于咱们认为前导数位的值永远为0,这个时候不管尾数的小数部分和指数部分怎么取,浮点数的值都不会是0。为此咱们规定,当指数位所有为0且尾数的小数位全为0时,这个时候浮点数的值为0。注意,+0和-0时两个不一样的浮点数,即便他们的数值同样,可是浮点数的表示方式不同。
当指数部分全为0,但时小数位不全为0的时候,这个时候浮点数表示的值就是非标准化的值。这个时候咱们认为该浮点数的前导数位为0,所以这个时候的单精度浮点数大小为(−1)s × 0.f × 2−126,双精度浮点数的大小为(−1)s × 0.f × 2−1022,其中s为符号位上的数值,2为底的指数分别是-126和-1022,而不是-127和-1023。具体缘由很简单,由于标准化所能表示的最小值是(−1)s × 1 × 2−126和(−1)s × 1× 2−1022。提出非标准化的目的就是为了表示更小的值从而提升精确度。
当指数位全为1,而尾数的小数部分全为0时表示+∞和−∞,同时经过符号位来区分+∞和−∞。因此采用IEEE 754标准表示浮点数能够很好的处理无穷大的状况。
NaN(Not a Number)用来表示非数字的值,当指数位全为1且尾数的小数部分不为0时表示NaN值。一共有两类NaN值,静态非数(QNaN, Quiet NaN)和警告非数(SNaN, Signalling NaN)。
在一个NaN的值中,若是尾数小数部分首位被置位则表示QNaN。QNaN是很重要的一类非数,四则运算常常传递QNaN值,该值一般表示不被数学上定义的运算结果,好比除数为零的时候。
在一个NaN的值中,若是尾数小数部分首位被置0则表示SNaN。它别用来表示操做中的一个异常,能够用来表示一个未被初始化变量的过早使用。
Reference:
[1] http://steve.hollasch.net/cgindex/coding/ieeefloat.html
[2] https://en.wikipedia.org/wiki/IEEE_754-1985