整数在内存中的存储
原码、反码、补码
计算机中的整数有三种2进制表示方法,即原码、反码和补码。三种表示方法均有符号位和数值位两部分。
-
原码(Sign-Magnitude):原码表示法是用最高位表示符号位,0表示正数,1表示负数,其余位表示数值的绝对值。例如,+5 的原码是 00000101,而 -5 的原码是 10000101。
-
反码(One's Complement):反码表示法中,正数的反码与原码相同,而负数的反码则是将其原码中的除符号位外的所有位取反。例如,+5 的反码和原码都是 00000101,而 -5 的反码是 11111010。
-
补码(Two's Complement):补码表示法中,正数的补码与原码相同,而负数的补码则是其反码加 1。例如,+5 的补码和原码都是 00000101,而 -5 的补码是 11111011。
为什么在计算机系统中,数值一律用补码来表示和存储?
原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。
1111 1011 (-5)
+ 0000 0011 (+3)
-------------
1111 1110 (-2)
补码 1111 1110-》取反码-》1000 0001》取补码》1000 0010,得到原码,及-2。
对于减法,我们可以将其视为加上一个数的负数。因此,对于减法 -3 + 5,我们可以将其转化为加法问题:
-3 的补码: 1111 1101 5 的补码: 0000 0101
相加所得补码:1 0000 0010
舍去溢出位,得到补码:0000 0010
大小端介绍
大端存储模式中,数据的高位保存在内存的低地址处,而数据的低位保存在内存的高地址处。这意味着在内存中,最高有效字节(Most Significant Byte,MSB)位于最低的地址处,而最低有效字节(Least Significant Byte,LSB)位于最高的地址处。
小端存储模式中,数据的低位保存在内存的低地址处,而数据的高位保存在内存的高地址处。这意味着在内存中,最低有效字节(LSB)位于最低的地址处,而最高有效字节(MSB)位于最高的地址处。
#include <stdio.h>
int main() {
unsigned int i = 1;
char *c = (char*)&i;
if (*c) {
printf("Little endian\n");
} else {
printf("Big endian\n");
}
return 0;
}
创建一个 unsigned int
类型的变量 i
并赋值为 1。然后,使用一个字符指针 c
将其地址强制转换为字符型指针。由于整数类型在内存中是以字节序列的形式存储的,我们可以通过检查这个字符指针所指向的地址处的值来确定机器的字节序。如果该地址处的值为非零,则表示该机器是小端存储(因为最低有效字节在最低地址处,所以 *c
不为零)。如果该地址处的值为零,则表示该机器是大端存储(因为最高有效字节在最低地址处,所以 *c
为零
浮点型在内存中的存储
浮点数存储规则
浮点数 V 可以表示为 (-1)^S * M * 2^E,其中:
- (-1)^S 是符号位。当 S = 0 时,V 为正数;当 S = 1 时,V 为负数。
- M 是有效数字(也称尾数),它是大于等于 1 且小于 2 的数。
- 2^E 是指数位。
列:
-7.0可以写成如下形式:
(-1)^1 * 1.75 * 2^2
其中:
- S=1(因为-7是负数)
- M=1.75(二进制为1.11,十进制为1.75)
- E=2(因为-7的绝对值的二进制表示中有两个0位数)
补充 :
要将十进制数 1.75 转换为二进制数,可以使用以下步骤:
- 将整数部分和小数部分分开。1.75 的整数部分是 1,小数部分是 0.75。
- 将整数部分转换为二进制数,使用除以2取余法。1 ÷ 2 = 0 余 1。所以第一个二进制数是1。
- 将小数部分转换为二进制数,使用乘以2取整法。0.75 × 2 = 1.5,所以第一个二进制数是1;然后,将剩余部分0.5继续乘以2,得到1;再次将剩余部分0.0继续乘以2,得到0。所以小数部分的二进制为0.11。
当涉及到32位的浮点数时,可以按照如下方式划分:
1位 | 8位 | 23位
---------------------------------
符号位s | 指数E | 有效数字M
当涉及到64位的浮点数时,可以按照如下方式划分:
1位 | 11位 | 52位
----------------------------------
符号位s | 指数E | 有效数字M
在IEEE 754中,对于有效数字M,即默认第一位总是1,因此可以被舍去,只保存后面的小数部分。这种表示方法称为"隐藏位"(hidden bit),它允许节省一个比特位,从而在单精度浮点数中将有效数字的位数从23位增加到24位。
例如,对于十进制数1.75,它的二进制表示为1.11,但是在IEEE 754中,只需要保存后面的.11部分,因为规定第一位1总是隐含的。所以,有效数字M的24位中,实际上只需要存储后面的两位,即11。
在IEEE 754浮点数中,指数E是一个无符号整数,但它的真实值存储时要加上一个中间数。这个中间数对于单精度浮点数(32位)是127,对于双精度浮点数(64位)是1023。这个中间数的目的是将可表示的指数范围平移到一个较小的范围内,使得指数既可以表示正数又可以表示负数,同时节省空间。
当指数E的值不全为0或不全为1时,在IEEE 754中采用如下规则来表示浮点数:
- 首先,将指数E的计算值减去中间数(127或1023),得到真实值。
- 然后,将有效数字M的前面加上第一位的1。
这个过程可以概括为以下几个步骤(二进制->小数):
- 将指数E的计算值减去中间数(127或1023),得到真实值。
- 将有效数字M的前面加上第一位的1(因为第一位默认为1,所以实际存储时省略了,需要补上)。
- 根据真实的指数值进行相应的移位操作,以确定浮点数的最终值。
继续以-7为例子:
-7.0可以写成如下形式:(-1)^1 * 1.11(二进制) * 2^2
因此,对于-7来说,它的IEEE 754表示形式为:
符号位S = 1(因为是负数)
指数E = 129(因为2^2的指数为2,加上中间数127得到真实值)
有效数字M = 11(111的二进制形式)
综合起来,-7的IEEE 754表示形式为:
1 10000001 11000000000000000000000
当指数E的值全为0或全为1时,在IEEE 754中采用如下规则来表示浮点数:
- 如果指数E全为0,则表示浮点数为非规格化数或者零。
- 如果指数E全为1,则表示浮点数为无穷大或者NaN(不是一个数字)。
具体来说:
- 当指数E全为0时,即E=0,表示浮点数为非规格化数或者零。此时,有效数字M前面的隐藏位1被保留,但指数E为0,意味着这个数是非规格化数,有效数字M的值小于1。这样,浮点数的表示形式就是:(-1)^S * M * 2^(-126),其中S是符号位。
- 当指数E全为1时,即E=1,表示浮点数为无穷大或者NaN(不是一个数字)。这时,有效数字M的值可能是0,也可能不为0,这取决于M的值。如果M为0,则表示浮点数为无穷大;如果M不为0,则表示浮点数为NaN。