整数与浮点数在内存中的存储

1,整数数据在内存中存储

在C语言中,整型类型(如intshort等)通常采用补码来表示有符号整数。这使得程序员能够使用标准的运算符(如+-*等)执行整数运算,而无需考虑底层的位表示。

1.1 源码,反码,补码

这三种表示方法均有符号位和数值位两部分组成且对于正整数而言,原反补码均相同

反码与补码的运算规则:以int类型举例最高位是0代表该数字为正数,最高位是1代表该数字为负数;反码规则为符号位不变,其他位按位取反;补码是反码加一得到补码

数据在内存中存储时,均存储补码,以int类型举例

1的原码,反码,补码均为:0000 0000 0000 0000 0000 0000 0000 0001

-1原码:1000 0000 0000 0000 0000 0000 0000 0001

-1反码:1111 1111 1111 1111 1111 1111 1111 1110

-1补码=反码+1:1111 1111 1111 1111 1111 1111 1111 1111

  则1+(-1)=1 0000 0000 0000 0000 0000 0000 0000 0000

此时发现数字变为33位,而int类型只有4个字节,32比特位,系统从低位向高位截取32个比特位,所得结果为32个0即为0;结果与事实相符

从上面我们得出补码的优点

  1. 相同的加法运算:使用补码,正数和负数的加法可以使用相同的加法器来实现。无需单独的减法器,从而简化了电路设计。

  2. 无符号表示兼容:补码同时支持有符号和无符号数的运算,因为在计算时负数能被转换为正数,简化了计算。

  3. 唯一性:补码对每个整数有唯一的表示,特别是负数,没有双重表示,这避免了某些额外的复杂性。例如,原码中0可以表示为正0和负0,而补码只用一个0表示。

 对于补码的运算

1.加法:两个补码相加时,如果结果的最高位(溢出位)丢失,结果就是正确的补码表示。

2.减法:减法可以转化为加法。减去一个数等同于加上该数的补码。

3.乘法和除法:虽然这些操作比较复杂,现代计算机通常使用特定的硬件操作来处理乘法和除法,但原理上依然基于补码的表示。

1.2 整型有无符号的区别

对整型家族而言,存在有无符号的区别,其内在逻辑在于有符号整型的最高位为符号位,而无符号整型全为数值位,故两者表示范围也不同,以char类型和unsigned char类型为例子:

char(有符号)的表示范围以十进制表示为:-128--127(下面展示部分数字的补码表示)

 1:0000 0001; 2:0000 0010 ... 127 :0111 1111; -1:1111 1111;-2:1111 1110 ...-127:1000 0001 ;-128:1000 0000

unsigned char表示范围以十进制表示为:0--256

2,浮点数在内存中存储

在C语言中,浮点数是以特定的格式存储的,通常遵循IEEE 754标准。这个标准定义了浮点数的表示方式,包括单精度(float)和双精度(double)等类型,浮点数表示范围在头文件<float.h>中

2.1浮点数的结构

浮点数由三部分组成

  • 符号位 S(sign bit):1位,用于表示数值的正负。
  • 指数部分 E(exponent):用于表示浮点数的大小。浮点数可以通过调整指数部分来表示非常大的或非常小的数。
  • 尾数 M(mantissa or significand):也称为有效数字,表示实际的数值。
  • 表示浮点数的公式

    浮点数的表示可以通过以下公式计算其数值

 

对于双精度,公式中的偏移量会是1023,单精度的偏移量如图为127

2.2偏移量

  • 偏移量是一种常数,用来调整指数的范围。它可以让我们在存储时只使用非负数。
  • E为无符号整型。

  • 在单精度浮点数中:

    • 使用的偏移量是 127。也就是说,如果实际的指数是 -1,存储时会将其加上 127,存储为 126。
  • 在双精度浮点数中:

    • 使用的偏移量是 1023。同样的道理,实际的 -1 指数存储为 1022。

 如果一个浮点数的实际指数是 -2:

  • 在单精度中,存储的值 = -2 + 127 = 125
  • 在双精度中,存储的值 = -2 + 1023 = 1021

2.3 浮点数存储格式

以单精度浮点数(flaot)为例,存储格式如下

  • 符号位 (S):0 表示正数,1 表示负数。

  • 指数部分 (E):采用偏移量表示法(bias)。对于单精度,偏移量为127,因此实际存储的指数需要加上127。

  • 存储的指数 = 真实指数 + 127。

  • 尾数部分 (M):

    • 尾数以1.XXXXXX的形式存储,即只有在数值为正常化时,将1隐含在尾数前。尾数的实际存储是一个隐含的二进制“1”后跟23位有效数字。例如,如果尾数位的二进制是 10000000000000000000000,则实际的尾数为 1.10000000000000000000000(隐含的“1”加上尾数的内容)。

 我的个人理解为:M在存储中先将十进制数字转化为二进制数字,并以上面公式给出的方式表示出来,M部分只存小数点后面的部分,从左开始表示小数点后的数,表示完成后不够的位数向右补0,直到位数满足要求(在float类型中为23bit位)

例如十进制数5.5的二进制表示为101.1,即1.011*2的2次方 用公式表示时:S=0,E=2+127=129,M=011

即将其二进制存储为0(S) 1000 0001(E)    0110 0000 0000 0000 0000 000(M)

规范写为0100 0000 1011 0000 0000 0000 0000 0000

 表示-16.75:  16.75的二进制表示为1000.11 即1.00011*2的3次方 

S=1,E=3+127=130,M=00011

二进制表示为1 (S)1000 0010(E) 0001 1000 0000 0000 0000 000(M)

规范写为1100 0001 0000 1100 0000 0000 0000 0000

 2.4精度与范围

  • 精度

    • 单精度浮点数(float)有大约6-7位数字的精确度。
    • 双精度浮点数(double)有大约15-16位数字的精确度。
  • 范围

    • 单精度浮点数(float):约 3.4×10−383.4×10−38 到 3.4×10383.4×1038。
    • 双精度浮点数(double):约 1.7×10−3081.7×10−308 到 1.7×103081.7×10308。

注意,二进制小数点后第一位为2的-1次方,第二位为2的-2次方.....

且许多十进制小数无法用二进制精确表示,这个时候就需要大家,“努力”表示接近的数字了 

2.5 浮点数的特殊值

根据IEEE 754标准,浮点数还支持特殊的值。这些特殊值包括:

  • 0:正零和负零(符号位不同)。
  • 无穷大(Infinity):当数值超出浮点数可表示的范围时,结果为无穷大。表现为指数为全1,尾数为全0。
  • NaN(Not a Number):表示未定义的数值操作,例如 0/0 的结果。表现为指数为全1,尾数非零。

2.6浮点数运算

C语言中的浮点数运算遵循标准的算术规则,支持常见运算符:

  • +(加法)
  • -(减法)
  • *(乘法)
  • /(除法)

  2.7注意事项

  1. 精度问题:由于浮点数的有限精度,某些计算结果可能不是精确的数字。例如,0.1在浮点数表示中可能无法精确表示,导致比较时不等式成立。

  2. 舍入误差:浮点数运算可能引入舍入错误。程序员需要注意对浮点数的比较,尽量避免直接将两个浮点数进行相等比较。

  3. 选择合适的类型:对于需要高精度计算的应用,建议使用双精度(double),以减少因精度不足带来的误差。

 示例代码

#include <stdio.h>  

int main() {  
    float a = 0.1f; // 单精度  
    double b = 0.1; // 双精度  

    printf("单精度浮点数: %.20f\n", a); // 输出 20 位小数  
    printf("双精度浮点数: %.20f\n", b); // 输出 20 位小数  

    // 测试浮点数比较  
    if (a != b) {  
        printf("a和b不同\n");  
    }  

    return 0;  
}  

 可以复制代码验证,a与b的结果确实不同。

综上所述,整型和浮点型的存储方式不同,需要牢记两者区别,关键掌握如何计算二进制浮点数

int main()
{
    int n = 9;
    float* b = (float*)&n;
    printf("n的值为:%d\n", n);
    printf("b的值为:%f\n", *b);
    *b = 9.0;
    printf("n的值为:%d \n", n);
    printf("*b值为:%.10f\n", *b);

    return 0;
}

运行结果如图,第三行n的值并非空穴来风,用浮点数表示9.0并将其二进制序列以整型打印出来,就是这个结果

为了验证今日所学,我用了这个代码(非自己写),这个代码利用指针改变这块空间存储的数据类型实现了该功能,第一遍看没觉得巧妙,当自己去想办法验证时只

能得到这样的结果

或者这样。不知道n的整数值为什么两次不一样,为什么不全为0,且如果n为0.1,结果也为-1610612736。如果有佬看到这篇文章,还请教教我这个小萌新,一起学技术,共同进步。

我的第一篇博客,欢迎大家给出意见,不玻璃心,只求进步

  • 32
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值