signed和float类型数据编码

signed和float类型数据编码
计算机只能处理存储二进制数据,不管是字符、整数、小数,在计算机中同样是二进制数,只是系统将其做了不同的解释。对于无符号整数,存储到存储中的即是它的二进制表示,比如十进制数10对应二进制1010,十进制数30对应二进制11110。对于有符号数,我们需要考虑同时保存它的值和符号,通常使用最高位为1表示负号-,最高位0表示非负。

有符号整数

举个例子,char类型变量在内存中占用一个字节,8位二进制数,为了方便我们使用16进制表示,char类型可以存储0x00到0xff,总共256(十进制)个不同的值,最高位是1和0的分别有128个,即有128个负数和128个非负数。我们编程测试一下
char i = -1;
//强制转换为unsigned char变量
unsigned uc = (signed char)i;
printf(“16进制输出为,i:%x,ui:%x\n”,i,ui);

输出结果
在这里插入图片描述

出现这种情况,是因为%x 是int格式化符,i和ui被强制转换为int类型,i和ui变量所在的内存,都是存储的0xff,但是编译器将i的值解释为-1,强制转换为int型变量-1,16进制表示为0xffffffff,而ui变量被解释为255,强制转化后int型255,16进制表示为0x000000ff。事实上存储无符号数和有符号数,随着二进制的增加,十进制值也在增加,如果使用一个函数表示,二进制数是输入,十进制数是输出,这个函数是递增的。

0x0001028081fbfcfdfeff
char012-128-127-5-4-3-2-1
unsigned char012128129251252253254255

总结,计算机中的数据是通过补码的方式表示的,对于有效数字为n为的二进制数N,它的补码Ncomp表示为
N c o m p = N ( N 为 非 负 数 ) Ncomp = N (N为非负数) Ncomp=N(N)
N c o m p = 2 n + N ( N 为 负 数 ) Ncomp = 2^n + N (N 为负数) Ncomp=2n+N(N)

(char)-1是0xff,(short)-1是0xffff,(int)-1是0xffffffff。

32位float

浮点数有不同的标准,IEEE标准,单精度float使用4字节32位表示。基数为2,最高位是符号位,紧接着8位是阶码E,最后23位是尾数M,
最高位s 8位阶码 E 23位尾数M

阶码取值为【0,255】区间的整数,使用阶码的移码做基数的幂指数。
± 1. m ∗ 2 E − 127 ±1.m * 2^{E-127} ±1.m2E127
使用时,阶码减127做幂指数,23位尾数在最低位补0成24位二进制数做小数。 ( − 1 ) S ∗ ( 1 + M ∗ 2 ∗ 25 6 − 3 ) ∗ 2 ( E − 127 ) (-1)^S * (1 + M * 2 * 256^-3) * 2^(E-127) 1S(1+M22563)2E127)
举例
//想要给一块内存赋对应的二进制值,要把内存声明成整数类型,无符号和有符号都可以,但是无符号更符合我们的认知
//直接给非无符号整数类型( char int long float…)赋值十六进制和二进制当然不是非法的。但编译器会首先进行编码,然后写入内存


//比如,下面的float赋值,绝不是把32位存储的高3字节赋0,低8字节赋5
//编译器首先会把0x05,强制转换为浮点数5.0,
//然后按照浮点数编码标准编码,存在内存中。
float test = 0x00000005;
printf("%f\n",test);
//5.0存在float中的二进制形式是
unsigned int pui = (unsigned int)&test;
printf("%ux",*pui);

unsigned int ui32 = 0xc0000005;
//不要直接给float 赋值16进制数
float *f32 = &ui32;
printf("*pf是:%.22f\n",f32);

最高位S是1,这是一个负数,其次8位数是0x80,则2的幂指数128-127,最低23位是5,最低位补0 就是23位数左移一位,即使23位数乘以2,小数点后24位是0x0000A0。
使用16进制表示
− 1.0000 A 0 ∗ 2 = = > − ( 1 + 0 ∗ 25 6 − 1 + 0 ∗ 25 6 − 2 + 10 ∗ 25 6 − 3 ) ∗ 2 128 − 127 = -1.00 00 A0* 2 ==> -(1 + 0 * 256^{-1} + 0 * 256^{-2} + 10 * 256^{-3}) * 2^{128-127} = 1.0000A02==>(1+02561+02562+102563)2128127=
在这里插入图片描述

输出结果
在这里插入图片描述

如果按照阶码尾数的格式计算,不能表示浮点数0.0,所以浮点格式有特殊编码表示特殊值
一、0,指数部分全部为0,并且尾数全部为0,则表示为浮点0.0,并且规定-0 = +0。如果按阶码式子,此值为1.0 * 2^-127,不考虑符号位,这也是阶码能表示的最小值
二、指数部分全为0,尾数部分不为0,这是非规格值,计算机默认不会使用这些值编码浮点数。如果你手动填充内存,打印出来是0;
二、无限大,32位二进制值一直增加,到阶码全为1,尾数为0时,此时表示为无限大,根据符号位,分为+ref和-ref
三,NAN,阶码全为1时,尾数非0,此时表示NAN,则表示这个值不是一个真正的值(Not A Number),根据尾数M的最高位分为QNAN(1)和SNAN(0),QNAN一般表示未定义的算术运算结果,最常见的莫过于除0运算;SNAN一般被用于标记未初始化的值,以此来捕获异常。
所以,32位单精度浮点的有效范围只在区间
( − 2 128 , 2 128 ) (-2^{128},2^{128}) 2128,2128而不是
( − 2 ∗ 2 128 , 2 ∗ 2 128 ) (-2 * 2^{128},2 * 2^{128}) 22128,22128,更精确的说单精度浮点最大有效值编码为0x7F7FFFFF,最小值0xFF7FFFFF,有效范围区间
[ − ( 2 128 − 2 − 103 ) , 2 128 − 2 − 103 ] [-(2^{128}-2^{-103}), 2^{128}-2^{-103}] [(21282103),21282103]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值