(转http://www.cublog.cn/u/11557/showart_88175.html)
目前大多数高级语言(包括C)都按照IEEE-754标准来规定浮点数的存储格式,IEEE754规定,单精度浮点数用4字节存储,双精度浮点数用8字节存储,分为三个部分:符号位、阶和尾数。阶即指数,尾数即有效小数位数。单精度格式阶占8位,尾数占24位,符号位1位,双精度则为11为阶,53位尾数和1位符号位,如下所示:
单精度浮点数存储格式
s 指数 尾数
31 30 23 22 0
双精度浮点数存储格式 s 指数 尾数
63 62 52 51 0
单双精度各部分所占字节数量比实际存储格式都了一位,的确是这样,事实是,尾数部分包括了一位隐藏位,允许只存储23位就可以表示24位尾数,默认的1位是规格化浮点数的第一位,当规格化一个浮点数时,总是调整它使其值大于等于1而小于2,亦即个位总是为1。例如1100B,对其规格化的结果为1.1乘以2的三次方,但个位1并不存储在23位尾数部分内,这个1是默认位。
阶以移码的形式存储。对于单精度浮点数,偏移量为127(7FH),而双精度的偏移量为1023(3FFH)。存储浮点数的阶码之前,偏移量要先加到阶码上。前面例子中,阶为2的三次方,在单精度浮点数中,移码后的结果为127+3即130(82H),双精度为1026(402H)。
浮点数有两个例外。数0.0存储为全零。无限大数的阶码存储为全1,尾数部分全零。符号位指示正无穷或者负无穷。
float型变量:根据IEEE的浮点标准,一个浮点数应该用下述形式来表示:
V=(-1)^s * M * 2^E (公式1)
在C语言中,32位的float型变量有着这样的规定:首位表示符号位s,接下来的8位(指数域)用于表示2的指数E,剩余的23位(小数域)表示M(取值范围为[1,2)或[0,1))。除了上述规定以外,根据指数域的二进制表示情况不同,被编码的float型数字又可以分成三种情况——
1、规格化值。当指数域的8个二进制数字既非全零又非全1时,float数值就是这种情况。设指数域的八位二进制所表示的十进制数为e, 则公式1中的E就是 E = e - (2^7 - 1) (公式2);
而且此时,将小数域所表示的二进制假设为(f22)(f21)...(f1)(f0) (注2) ,则该小数域所表示的值即为f = 0.(f22)(f21)...(f1)(f0).于是M = 1 + f
2. 非规格化值。当指数域的8个二进制数字为全0时,float数值就为这种情况。这时指数域所表示的十进制数为0,规定指数值为 E = 1 - (2^7 - 1),也就是E为定值-126;此时小数域的值仍表示f = 0.(f22)(f21)...(f1)(f0),但是M的值却变成M = f。
3. 特殊值。当指数域的8个二进制数字为全1时即为这种情况。当小数域为全零时,该float值根据符号位的不同表示正无穷或者负无穷;当小数域为非全零时,该float值为NaN(Not a Number)。
与整形的转换
问:怎么把数组 32位浮点型 转换为8位整形?
32位浮点的二进制存储是1位符号为,8为指数位,23为尾数位,如何将一个浮点数转换成二进制呢比如12.5首先整数部分12的二进制计算用12/2的余数转换得到二进制1100,而小数部分0.5,用0.5*2后的整数部分进行计算得到.1000000,最后12.5的表示为1100.1000000000000000000000000,再将小数点左移动3位,1.10010000000000000000000000000,计算指数,指数的基准是127,该数的指数应该是127+3=130,二进制为10000010,由于12.5是整数则符号位为0,整个12.5的二进制表示为01000001010010000000000000000000,这就是32位浮点的二进制过程,那么我们把32位传换成8位就反向推这个过程。先取出指数的8位,换算成数值,减去127,得到具体移动的小数点位数,然后将后面23位的小数点向右移动该位数,小数点左边部分就是整数部分。
32位浮点数存储的范围远远大于8位整形,所以存在溢出情况