您的位置:首页 > 理论基础

一道面试题引发的问题:浮点数和整数在计算机种的存储方式

2014-07-18 13:42 295 查看
1.先看题目:

给出下面代码的输出:

[html] view
plaincopy

float a = 1.0f;

cout << (int)a << endl;

cout << (int&)a << endl; // (int&)a , 是什么意思呢?

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;

结果也给你吧:

[html] view
plaincopy

1

1065353216

false

0

0

true

如果不知道(int&)a是什么意思,你可能会猜测它表示变量a的地址转化为十进制表示(地址一般是十六进制表示的,int将其强制转化为十进制)。这样的话,第二行每次打印出来的数应该是不同的,但是第二行打印的始终是1065353216;而且按上面的理解,(int&)b打印出来也不应该是0。

其实,(int&)a表示把a地址处的4个字节强制转换成长int型4个字节,那么为什么1.0f存储后转为int变成1065353216呢?这就涉及到整型和浮点型数在计算机里存储方式的问题了,见下。

2.浮点数和整数在计算机种的存储方式

(1)整数的存储方式:计算机用二进制来表示整数,最高位是符号位;

(2)浮点数的存储方式:

以intel的处理器为例,并且方便起见,这里只以float型为例——从存储结构和算法上来讲,double和float是一样的,不一样的地方仅仅是float是32位的,double是64位的,所以double能存储更高的精度。由于Intel
CPU的架构是Little Endian(请参数机算机原理相关知识),所以它是按字节倒序存储的。但是这里先不考虑逆序存储的问题(省得被搞晕了),后面你会发现存储顺序不影响我们这里要讨论的转换问题。

首先了解如何用二进制表示小数(也就是如何把十进制小数转化为二进制表示):

举一个简单例子,十进制小数 10.625

1)首先转换整数部分:10 = 1010b

2)小数部分0.625 = 0.101b

(用“乘2取整法”:0.625*2=1.25,得第一位为1,0.25*2=0.5,得第二位为0,0.5*2=1, 得第三位为1,余下小数部分为零,就可以结束了)

3)于是得到 10.625=1010.101b

4) 类似十进制可以用指数形式表示:

10.625=1.0625*(10^1)

所得的二进制小数也可以这样指数形式表述:

1010.101b=1.010101 * (2^3)

也就是用有效数字a和指数e来表述: a * (2^e),现在我们要的尾数和指数都出来了。显而易见,最高位永远是1,所以这个1我们还有必要保留他吗?当然没有必要!好的,删掉他。这样尾数的二进制就变成了:010101*(2^3)(注意前面是有小数点的,但是既然一定有小数点,那这个小数点也是没有必要保存的)。

用一个32bit的空间(bit0~bit31)来存储这么一个浮点数,分配存储空间如下:

bit0~bit22 共23bit,用来表示有效数字部分,也就是a,本例中补全后面的0之后 a变为010 1010 0000 0000 0000 0000

bit23~bit30 共8个bit,用来表是指数,也就是e,范围从-128到127,实际数据中的指数是原始指数加上127得到的,如果超过了127,则从-128开始计,所以这里e=3表示为130

bit31 为符号位,1表示负数,这里应该为0

把上述结果填入32bit的存储器,就是计算机表示小数10.625的形式。

注意这个例子的特殊性:它的小数部分正好可以用有限长度的2进制小数表示,因此,而且整个有效数字部分a的总长度小于23,因此它精确的表示了10.625,但是有的情况下,有效数字部分的长度可能超过23,甚至是无限多的,那时候就只好把后面的位数截掉了,那样表示的结果就只是一个近似值而非精确值;显然,存储长度越长,精度就越高,比如双精度浮点数长度为64位,1位符号位,11位指数位,52位有效数字。

3.回到原题

回到原题,我们的1.0f按以上方式存储到计算机是什么样子的呢?简单重复下刚刚的步骤:

1.0f=1.0b,转化为指数形式为:1.0*(2^0),去掉首位置的1和小数点,补全0之后,bit0~bit22位如下:000 0000 0000 0000 0000 0000;

指数原本为0,但是要加上127,所以bit23 - bit30位如下:0111 1111;

1.0f为整数,所以符号位为0

最终1.0f在计算机中存储为:0011 1111 1000 0000 0000 0000 0000 0000,转化为十进制试下,看看是不是1065353216?!(*^__^*)

至于(int&)b,0在计算机中存储为32位全0,这是约定的(你会发现0没法像2中方法存储)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: