目录 一、背景二、int类型分析1、分析2、验证(汇编) 三、float类型分析1、分析2、验证(汇编)
一、背景 这几天在写《算法设计与分析的作业》期间遇到了用int和float类型最大值,初始化变量的问题。查了一下,int可以用<limits.h>中的INT_MAX初始化,float可以用<float.h>中的FLT_MAX初始化,但是我就很难受,为什么都是基本类型的最大值,却要包含两个头文件,能不能偷懒,用int最大值直接去初始化float或者float最大值初始化int呢?按照以前的错误理解,int和float字节数相同,但是float有小数部分,所以它表示的范围更窄,我呢就写了一个程序看了下,这两个到底相差多大,偷懒的做法风险有多高,所以就写了下面的程序: #include <iostream>#include <limits.h>#include <float.h>using namespace std;int main(){ cout<<INT_MAX<<endl; cout<<FLT_MAX<<endl; return 0;}
结果如下:
果然是我太菜了,那就好好看下到底是怎么回事吧: 二、int类型分析 1、分析 int 用4字节保存,最多表示 2 4 ∗ 8 = 2 32 2^{4*8} = 2^{32} 24∗8=232, 有正数和负数,所以可表示 2 31 − 1 2^{31}-1 231−1个正数,即其最大值为2147483647,和上面结果一致,最小值-2147483648, 最大值比最小值的绝对值小1, 这是因为0占据了正数的一个表示名额。具体如下: 012345678910111213141516171819202122232425262728293031总共32位,也就是说它的能存储的数字就是32位全0,到32位全1。如果这 样的话它就只能存储正数了,但是我们计算也要用到负数,这可不太妙啊。所以为了能够即能存储正数又能够存储负数,科学家在设计计算机的时候把这32位数据进行了重新解释,从全0开始,一直到, 除最前一位之外,其余位都为1,这些表示他们对应的正数。就是下面这种形式
从全0 00000000000000000000000000000000
到除第一位是0之外全都是1
01111111111111111111111111111111上面范围都表示正数。可以计算一下,上面这个数刚好就是对应的最大的int类型。
剩下的都表示负数了,那么问题又来了,这些负数有分别是怎么表示的呢?我们接着上面的分析,最大的正数表示形式(就是上面写出来的除第一位是0之外全都是1的那个形式)在加一,就成了下面的样子: 10000000000000000000000000000000
这个数被计算机解释为最小的负数,就是-2147483648,然后依次类推,32的表示形式每加1, 它所表示的形式也就加1,一直到最大的负数-1,32位表示形式就成了全1
11111111111111111111111111111111好了关于int存储大致解释清楚了,但是我掌握的这些到底对不对呢?下面我们使用汇编来看一下,到底是不是这样:
2、验证(汇编) 这里用mips汇编来查看其存储方式, 把下面这段代码在汇编器Qtspim中运行(运行前请先删除汉字注释): .dataint_1: .word 0 ;定义了一个4字节的变量int_1,并把它赋值为0int_2: .word 2147483647;定义了一个4字节的变量int_2,并把它赋值为2147483647int_3: .word -1;定义了一个4字节的变量int_3,并把它赋值为-1int_4: .word -2147483648;定义了一个4字节的变量int_4,并把它赋值为-2147483648.textmain: lw $t1,int_1;把上面定义的变量int_1取值到寄存器t1中 lw $t2,int_2;把上面定义的变量int_2取值到寄存器t2中 lw $t3,int_3 lw $t4,int_4查看寄存器情况如下:
和上面解释的情况相同。
也就是说第一个位置是符号位,如果它为0表示正数,为1表示负数第2-9位共8个位是指数位,这里的指数位使用的是带偏阶的计数法1,就是说,这里存储的指数 = 真正指数+127,这里的127是它的偏阶。那么它最大能够存储多大的指数呢,8位最多能表示 2 8 − 1 2^{8}-1 28−1个数字也就是255个数字,从全0(0)到全1(255)。但是IEEE754的指数全1是不能表示数字的;真正指数 = 这里存的指数-127,所以最大能够存储的指数是254-127 = 127,最小能够存储的指数是1-127 = -126,这里最小用了1减,而没有用0,是因为当指数为0,而尾数非0,这不是规格化数。所以最终指数部分能够表示的范围是-126 ~ 127在看尾数部分,IEEE754隐藏了一个前导1,也就是说,这里存储的尾数 = 真正尾数 - 1,所以我们在将存储的数据还原为原先的数据时一定要加上1. 2、验证(汇编) .datafloat_1: .float -0.5float_2: .float 0.0float_3: .float 3.1875.textmain: lw $t1,float_1 lw $t2,float_2 lw $t3,float_3
结果如下:
结果分析:
具体可以看这本书计算机组成与设计这里面第三章有一部分讲的是浮点表示很有用。 ↩︎