1、以下两条输出语句分别输出什么?
float a = 1.0f; cout << (int)a << endl; cout << (int&)a << endl; cout << boolalpha << ( (int)a == (int&)a ) << endl; // 输出什么? float b = 0.0f; cout << (int)b << endl; cout << (int&)b << endl; cout << boolalpha << ( (int)b == (int&)b ) << endl; // 输出什么?
解析:
(int)&a :把a的地址强制转换成整型 (int&)a :把a强制转换成整形引用类型,相当于是某个整形引用,引向了a所在的32位内存区域,并将这32位当做一个整数;(int &)a的意思是将a存储单元开始的内容解释为一个int引用。 (int)a :a在内存中的值转换成int类型;(int)a 是数值意义上的转换。
分析:这个题目涉及float在计算机中的存储问题, IEEE 754的标准就是描述的这个问题。如果这个题目放在笔试的时候应该比面试的时候容易多了。
1、了解:
目前C/C++编译器标准都遵照IEEE制定的浮点数表示法来进行float,double运算。这种结构是一种科学计数法,用符号、指数和尾数来表示,底数定为2——即把一个浮点数表示为尾数乘以2的指数次方再添上符号。下面是具体的规格:
符号位 阶码 尾数 长度 float 1 8 23 32 double 1 11 52 64
无论是单精度还是双精度在存储中都分为三个部分:
1. 符号位(Sign) : 0代表正,1代表为负 2. 指数位(Exponent):用于存储科学计数法中的指数数据,并且采用移位存储 3. 尾数部分(Mantissa):尾数部分
以单精度的浮点型为例:
指数部分(E) 占用8-bit的二进制数,可表示数值范围为0-255。 但是指数应可正可负,所以IEEE规定,此处算出的次方须减去127才是真正的指数。所以float的指数可从 -126到128. 尾数部分(M)实际是占用24-bit的一个值,由于其最高位始终为 1 ,所以最高位省去不存储,在存储中只有23-bit。 符号位:s 通过(-1)的s次幂来表示正负号。
以下通过几个例子讲解浮点数如何转换为二进制数
例一:
已知:整数3490593(16进制表示为0x354321)。
求:其对应的浮点数3490593.0的二进制表示。
解法如下:
先求出整数3490593的二进制表示:
H: 3 5 4 3 2 1 (十六进制表示)
B: 0011 0101 0100 0011 0010 0001 (二进制表示)
│←───── 21────→│
即:
1.1010101000011001000012×221
可见,从左算起第一个1后有21位,我们将这21为作为浮点数的小数表示,单精度浮点数float由符号位1位,指数域位k=8位,小数域位(尾数)n=23位构成,因此对上面得到的21位小数位我们还需要补上2个0,得到浮点数的小数域表示为:
1 0101 0100 0011 0010 0001 00
float类型的偏置量Bias=2k-1-1=28-1-1=127,但还要补上刚才因为右移作为小数部分的21位,因此偏置量为127+21=148,就是IEEE浮点数表示标准:
V = (-1)s×M×2E
E = e-Bias
中的e,此前计算Bias=127,刚好验证了E=148-127=21。
将148转为二进制表示为10010100,加上符号位0,最后得到二进制浮点数表示1001010010101010000110010000100,其16进制表示为:
H: 4 A 5 5 0 C 8 4
B: 0100 1010 0101 0101 0000 1100 1000 0100
|←──── 21 ─────→ |
1|←─8 ─→||←───── 23 ─────→ |
这就是浮点数3490593.0(0x4A550C84)的二进制表示。
例二:
0.5的二进制形式是0.1
它用浮点数的形式写出来是如下格式
0 01111110 00000000000000000000000
符号位 阶码 小数位
正数符号位为0,负数符号位为1
阶码是以2为底的指数
小数位表示小数点后面的数字
下面我们来分析一下0.5是如何写成0 01111110 00000000000000000000000
首先0.5是正数所以符号位为0
再来看阶码部分,0.5的二进制数是0.1,而0.1是1.0*2^(-1),所以我们总结出来:
要把二进制数变成(1.f)*2^(exponent)的形式,其中exponent是指数
而由于阶码有正负之分所以阶码=127+exponent;
即阶码=127+(-1)=126 即 01111110
余下的小数位为二进制小数点后面的数字,即00000000000000000000000
由以上分析得0.5的浮点数存储形式为0 01111110 00000000000000000000000
注:如果只有小数部分,那么需要右移小数点. 比如右移3位才能放到第一个1的后面, 阶码就是127-3=124.
此处主要参考:http://blog.163.com/yql_bl/blog/static/847851692008112013117685/
2、问题的解答
对于1.0f这个数字,根据上述例子可以对进行分解整数部分和小数两部分处理,整数部分:1,它的二进制位1;小数部分为.0,它的二进制为.0。因而这个数字的二进制数为1.0。 由于1.0f为正数,因而符号位为0,即S=0; 再求阶码位: 1.0 = 1.0X2^0。即e=0,E = e + 127 = 0 + 127 = 127.转为二进制 0111 1111 再求尾数: 小数位为0,由于浮点型的尾数是23位,因而补零。M = 000 0000 0000 0000 0000 0000 最后得出浮点型1.0f的二进制表示,也就是说它的浮点数存储形式为0011 1111 1000 0000 0000 0000 0000 0000(0x3f800000)
(int)a :a在内存中的值转换成int类型;(int)a 是数值意义上的转换。因此(int)a 为1.
(int&)a :把a强制转换成整形引用类型,相当于是某个整形引用,引向了a所在的32位内存区域,并将这32位当做一个整数;(int &)a的意思是将a存储单元开始的内容解释为一个int引用。因此(int &)a是将它的浮点数存储内容(0x3f800000)转换成一个整型(106535216).
因而整个题目的答案为:1,1065353216(0x3f800000),false,0,0,true。