c语言单精度和双精度存储方式以及移位存储的优点

存储方式

方式 位数 标准 模式
float 32bit IEEE R32.24
c语言单精度和双精度存储方式以及移位存储的优点_第1张图片
float.png
double 64bit R64.53
c语言单精度和双精度存储方式以及移位存储的优点_第2张图片
double.png
  1. 符号位(Sign):0代表正,1代表为负;
  2. 指数位(Exponent):用于存储科学计数法中的指数数据,并且采用移位存储;
  3. 尾数部分(Mantissa):尾数部分

R32.24和R64.53的存储方式都是用科学计数法来存储数据的
用二进制的科学计数法第一位都是1,可以将小数点前面的1省略,所以23bit的尾数部分,可以表示的精度却变成了 24bit,道理就是在这里。

那24bit能精确到小数点后几位呢,我们知道9的二进制表示为1001,所以4bit能精确十进制中的小数点后一位,24bit就能使float能精确到小数点后6位,而对于指数部分,因为指数可正可负,8位的指数位能表示的指数范围就应该为:-127-128了, 所以指数部分的存储采用移位存储,存储的数据为元数据+127。

下面就看看8.25和120.5在内存中真正的存储方式:

8.25换算成二进制科学计数法

8 = 1000;
0.25 = 0.01;

8.25(10) = 1000.01(2) = 1.00001*2^3 

  
按照上面的存储方式
符号位为   0,表示为正;
指数位为   3+127=130,
尾数部分为 00001 = 00001000000000000000000 //23位
故8.25的存储方式如下:
0--10000010--00001000000000000000000  
即01000001000001000000000000000000 


#同理

120.5在内存中的存储格式如下 
0--10000101--11100010000000000000000

即01000010111100010000000000000000 
 

那么如果给出内存中一段数据,并且告诉你是单精度存储的话,你如何知道该数据的十进制数值 呢?其实就是对上面的反推过程,比如给出如下内存数据:

01000001001000100000000000000000 
第一步:符号位为0,表示是正数;  
第二步:指数位为10000010,换算成十进制为130,所以指数为130-127=3; 
第三步:尾数位为01000100000000000000000,换算成十进制为 (1+1/4+1/64);
#尾数部分都要+1  
十进制数值为:2^3*(1+1/4+1/64)=8+2+1/8=10.125

移位存储的详解

以32位单精度float内存模型为例

c语言单精度和双精度存储方式以及移位存储的优点_第3张图片
float-struct.png

从上图可以看出 指数部分8位存储空间实际上并不在意同一个字节上,通常情况下8位存储空间可以存储的数值范围为

0000000 0 ~ 1111111 1

也就是从0开始到 255结束,一共 256个数。

但是新组成的8位数是用来表示整串32位单精度浮点数的幂指数(阶码)的,而浮点数的幂指数(阶码)是有必要使用负数的。

既要表示正数,又要表示负数,因此我们要拿出一位来表示正负号,通常都是拿一个字串最左边的那位即最高位来表示正负号的,使用传统的方式,即一个字节的最高位(最左边那位)为1时表示负数,那么我们可以得到两个区间,这里我们为了看着方便还是使用空格来隔开最高位的符号位和最低位的那位特殊位:

第一个区间:

0 000000 0~ 0 111111 1

即+ 0 到 127,

第二个区间:

1 000000 0~ 1 111111 1

即 -0 到 - 127,

这里出现了2个0,一个正+0,一个-0

使用移位存储方式会有什么效果呢? 移位存储要+127 , 存储示例:

127 使用这个新生成的字节来表示,则是:

0 111111 1 ,


如果我们要表示 0,则有 0+127=127 即 0 111111 1

:0 000000 0 + 0 111111 1= 0 111111 1


我们要表示1,则有 1+127=128 即 1 000000 0

:0 000000 1 + 0 111111 1= 1 000000 0

我们要表示 2,则有 2+127=129 即 1 000000 1

:0 000001 0 + 0 111111 1= 1 0000001

………………………………………………………………

我们要表示 128,则有 128+127=255 即 1 111111 1

:1 000000 0+ 0 111111 1= 1 111111 1

这个128是我们能够使用 8位二进制移位存储算法表示的最大的正数了,再大就溢出了。 同样,我们来看看负数:

我们要表示 -1时,则有( -1) +127=127-1=126 即 0 111111 0

:0 111111 1 - 0 000000 1= 0 111111 1

我们要表示 -2时,则有( -2)+ 127=127-2=125 即 0 111110 1

:0 111111 1 - 0 000001 0= 0 111110 1

……………………………………………………………………………………………… 我们要表示 -127时,则有(-127)+127=127-127=0 即 0 000000 0

:0 111111 1 - 0 111111 1= 0 000000 0

这-127,是我们能够使用 8位二进制采用移位存储所能表示的最小的负数了,再小就溢出。

由上面的 例子,我们可以得出规律,采用移位存储技术,我们可以使用 8位二进制来表示从 -127~128 共计:

127个负数+零(0)+128个正数=256个数

看来使用移位存储即没有+0和-0的问题,又充分的使用这个新生成的 8位二进制数来最大限度的表示单精度浮点数的幂指数(阶码),是非常合理的

你可能感兴趣的:(c语言单精度和双精度存储方式以及移位存储的优点)