计算机组成原理:IEEE754标准中,为什么指数真值e变成阶码加上的偏移值是
127不是128?
1.浮点数在计算机⾥的存储⽅式
以32位为例,短浮点型float,按照按照 IEEE754 标准,在计算机⾥的存储格式如下
数符S:表⽰浮点数的符号,占1位,0—正数、1—负数;
小数的原码
尾数M:23位,原码纯⼩数表⽰,⼩数点在尾数域的最前⾯;
阶码E:8 位,采⽤有偏移值的移码表⽰;
移127码,即E=e+127,E的8位⼆进制数即为移127码的编码;
浮点数的真值:N=(-1)S×(1.M)×2^(E-127)\
2,按照移码的定义,k位原码的移码应该是: 真值+2^(K-1) 那么8位阶码应该是加128才对.那为什加的是127呢?
⾸先,我们知道移码是真值的⼀种去符号话的表⽰,阶码之所以⽤移码是因为移码值⼤的指数就⼤,通俗点就是把负数范围的数变成正数,⽅便⽐较.
规格化
对于将某个实数表⽰为计算机浮点数,⾸先要将其正规化,也就是表⽰为形如:
的样⼦。其中b是0或1,⽽p⼆进制数表⽰的指数位。这样,假设想表⽰为单精度(float)的浮点数,那么:
第⼀位符号位⽤0表⽰正,⽤1表⽰负
将指数p加上移码表⽰为8位的⼆进制数
在接下来的23位填充位数b部分。由于正规化表⽰时,最左边部分总是1,所以我们只需表⽰23位的尾数即可.
所以,在规格化表⽰中8位移码理论上可以表⽰的表⽰范围为0~ 255,但是IEEE754中⼜规定,当阶码为00000000,尾数也为0的时候表⽰真值为0,结合S符号位,有正0和负0之分;⽽当阶码为11111111,尾数为0时,表⽰真值为⽆穷⼤,结合S符号位,有正⽆穷⼤和负⽆穷⼤,但是为了在规格化的浮点数中规避掉这种情况,所以将偏移值选择127,⽽不选128;这样阶码就变成1~ 254,对应的指数值就为-126~127;这也就解释了为什么偏移值要选择127,⽽不选择128的原因了.
那么问题来了,既然把那些特殊值给规避掉了,那么他们该如何表⽰呢?
按照上⾯的浮点数表⽰⽅法,我们发现并不能表⽰出数值0的⼤⼩。因为我们认为前导数位的值永远为0,这个时候⽆论尾数的⼩数部分和指数部分怎么取,浮点数的值都不会是0。为此我们规定,当阶码全部为0且尾数的⼩数位全为0时,这个时候浮点数的值为0。注意,+0和-0时两个不同的浮点数,即使他们的数值⼀样,但是浮点数的表⽰⽅式不⼀样。
⾮标准化的值
当指数部分全为0,但时⼩数位不全为0的时候,这个时候浮点数表⽰的值就是⾮标准化的值。这个时候我们认为该浮点数的前导数位为0,因此这个时候的单精度浮点数⼤⼩为(−1)^s × 0.M × 2 ^−126,具体原因可以这样理解,⾮标准化可以看做是标准化的特殊情况,这时候阶码去0,但是因为是⾮规格化,所以不是默认隐藏了⼀位1,可以看成规格化还要向右移动⼀位.所以,指数就变成了126,其实⾮规格化就是在规格化的基础上扩展了精度.
⽆穷⼤
当指数位全为1,⽽尾数的⼩数部分全为0时表⽰+∞和−∞,同时通过符号位来区分+∞和−∞。所以采⽤IEEE 754标准表⽰浮点数可以很好的处理⽆穷⼤的情况。
⾮数字(NaN)
NaN(Not a Number)⽤来表⽰⾮数字的值,当指数位全为1且尾数的⼩数部分不为0时表⽰NaN值。⼀共有两类NaN值,静态⾮数(QNaN, Quiet NaN)和警告⾮数(SNaN, Signalling NaN)。当阶码为255时尾数不为0的时候,表⽰的数值就为NaN,
他的⽬的就是让程序员能够退持进⾏测试和判断的时间.
补充⼀点,虽然说java中, float类型占4个字节但是它表⽰数的范围从2^-126~2 ^127,⽽long类型占8个字节,其取值范围为long的最⼤值有符号是 2 ^63-1,⽆符号是2 ^64-1,因此float类型要⽐long类型表⽰范围⼤得多,因为float是存储的指数,⽽long类型是直接存放数的⼆进制原码.