进制
10进制、二进制、八进制、十六进制在编程中的表现形式
N
进制 逢 N
进 1
, 本身变为 0
; 如下表格 ,每个单元格从上之下 依次为 十进制,二进制,八进制,十六进制
1 0001 001 01 |
2 0010 进1,变0 002 02 |
3 0011 003 03 |
4 0100 004 04 |
5 0101 005 05 |
---|---|---|---|---|
6 0110 006 06 |
7 0111 007 07 |
8 1000 010 进1,变0 08 |
9 1001 011 09 |
10 1010 012 0a |
11 1011 013 0b |
12 1100 014 0c |
13 1101 015 0d |
14 1110 016 0e |
15 1111 017 0f |
16 0001 0000 020 10 进1,变0 |
17 0001 0001 021 11 |
18 0001 0010 022 12 |
19 0001 0011 023 13 |
20 0001 0100 024 14 |
十进制
十进制,编程中 输入的 int 类型默认为十进制
二进制,数字前面加上 0b 表示二进制 ;(b 为二进制binary的翻译)
- 二进制的数字 没有占位符,需要自定制输出方法
拓展: ``` 二进制数据: 1 1 1 1 1//数字前面加上 0b 即表示二进制数据 int num2 = 0b1101; printf("num2 == %d\n",num2);//13
16 8 4 2 1
- 二进制的数字 没有占位符,需要自定制输出方法
N位二进制的取值范围
1位 取值范围 0~1 0~2的1次方-1
2位 取值范围 0~3 0~2的2次方-1
3位 取值范围 0~7 0~2的3次方-1
n位 取值范围 0~2(n)-1
<a name="nXYZb"></a>
#### 八进制
- 八进制,数字前面加上 **0** 表示八进制
- 占位符 `%o` ,表示 以八进制的方式输出整数
```c
/*
13 = 8 + 5
10 5
10:表示逢八进一,本身变为0
5:低位为5
*/
int num3 = 015;
//以 十进制 输出 8 进制的整数
printf("%d",num3);//13
//以 八进制 输出 10进制的整数
printf("%o",13);// 015
十六进制
- 十六进制,数字前面 加上 0x
- 占位符
%x
,表示 以 16进制输出一个整数int hexNum = 0xd; printf("%d",hexNum);//13 printf("%x",13);//d
- 占位符
进制转换
十进制 ->
二进制
- 转换规则:
除 2 取余,倒叙读取
``` 13 - 除2 取余 13/2 6…1 6/2 3…0 3/2 1…1 1/2 0…1
- 倒叙读取
1101
13 的二进制 为 1101
<a name="aF3DV"></a>
#### 二进制 `->` 十进制
- 转换规则: `乘以 2 的 N次幂 ,求和` (从低往高的索引值)
1101 1 2(0) = 1; 0 2(1) = 0; 1 2(2) = 4; 1 2(3) = 8; N:索引值,从低往高 求和 : 1 + 0 + 4 + 8 = 13
<a name="Z35fj"></a>
#### 二进制 `->` 八进制
进制越大表示的位数就越短
- 3个二进制位 代表一个 8进制位 (因为 三个二进制位 111 最大值为7,8进制 逢八进一)
十进制 20 二进制 0001 0100 000 010 100 //三个二进制位 表示一个八进制 八进制 0 2 4 024
<a name="Yi8kK"></a>
#### 二进制 `->` 十六进制
- 4个二进制位 代表一个16进制位 (因为4位的最大取值是15, 而十六进制是逢十六进一)
十进制 20 二进制 0001 0100 十六进制 1 4 0x14
<a name="gYW2o"></a>
### 原码 补码 反码

<a name="Dy51W"></a>
#### 正数
- 将 **11** 存储到内存中
11 -> 二进制 [11 -> int = 4字节 = 32位 ;1字节 = 8位] 原码 : 0000 0000 0000 0000 0000 0000 0000 1011 反码 : 0000 0000 0000 0000 0000 0000 0000 1011 补码 : 0000 0000 0000 0000 0000 0000 0000 1011
- 正数的 `原码、反码、补码 ` 都是一样的, `“三码合一”`
<a name="qZhvO"></a>
#### 负数
- 将 -**11** 存储到内存中
- 二进制的第一位表示符号位。第一位是:
- **0**,表示正数
- **1** ,表示负数
-11 -> 二进制
原码 : 1000 0000 0000 0000 0000 0000 0000 1011
反码 : 符号位不变,其他位取反(0->1;1->0)
1111 1111 1111 1111 1111 1111 1111 0100
补码 : 反码 + 1
1111 1111 1111 1111 1111 1111 1111 0100
+ 0000 0000 0000 0000 0000 0000 0000 0001
补码 = 1111 1111 1111 1111 1111 1111 1111 0101 //内存中 存储的即补码
<a name="tJbvF"></a>
##### 原码 :负数的原码即其正数的二进制原码,然后将第一位符号位 改成 1
<a name="88xNo"></a>
##### 反码 :负数的反码,符号位不变,其他位根据原码取反
<a name="OR6Po"></a>
##### 补码 :负数的补码 = 反码 + 1
<a name="dAzV1"></a>
### 位运算

位运算:是针对二进制
<a name="VkzvL"></a>
#### 按位与
- `&` 按位与
- 特点:只有对应的两位都是 `1` 才返回 `1` ,否则返回 0
- 口诀:一假则假
- 规律:任何数按位与上1结果还是那个数
```c
int result1 = 9 & 5;
/**
9 : 1001
& 5 : 0101
-----------
0001
*/
printf("result1 = %d\n",result1);//1
按位或
|
按位或^
按位异或- 特点:对应两位 不相同 返回1,相同返回0
```c
int result3 = 9 ^ 5;
/**
9 : 1001
^ 5 : 0101
/ printf(“result3 = %d\n”,result3);//12 /根据 按位异或 的规律 可以得出:*/ //1、多个整数按位异或的结果和顺序无关 printf(“result = %d\n”,9 ^ 8 ^ 5);//4 printf(“result = %d\n”,9 ^ 5 ^ 8);//4 //2、相同整数按位异或结果是0 printf(“result = %d\n”,9 ^ 9);//0 //3、任何整数按位异或上0结果不变 printf(“result = %d\n”,9 ^ 0);//9 //4、任何整数按位异或上另一个整数两次结果还是那个数 printf(“result = %d\n”,9 ^ 5 ^ 5);//91100
- 特点:对应两位 不相同 返回1,相同返回0
```c
int result3 = 9 ^ 5;
/**
9 : 1001
<a name="gWbMR"></a>
#### 取反
- `~` 取反
- 特点:0变1 ;1变0
```c
int result4 = ~9;
/**
0000 0000 0000 0000 0000 0000 0000 1001
~ => 1111 1111 1111 1111 1111 1111 1111 0110 //取反之后 是补码 反码 = 补码-1
- 0000 0000 0000 0000 0000 0000 0000 0001 //
1111 1111 1111 1111 1111 1111 1111 0101 // 这步是反码
1000 0000 0000 0000 0000 0000 0000 1010 // 这步是原码 转成二进制 -10
*/
printf("result4 = %d\n",result4); // -10
左移
<<
左移a << n
,把 a 的二进制位 往左边 移 n 位,结果为a * 2(n次幂)
```c //移出的位砍掉,低位补0, 发现左移会把原有的数值变大 printf(“result = %d\n”, 9 << 1);//18 printf(“result = %d\n”, 9 << 2);//36 printf(“result = %d\n”, 9 << 3);//72 / 0 : 0000 0000 0000 0000 9 : 0000 0000 0000 1001 : 0000 0000 0001 0010 //左移1位 18 = 9 2(1) : 0000 0000 0010 0100 //左移2位 36 = 9 2(2) : 0000 0000 0100 1000 //左移3位 72 = 9 2(3) */
//左移的应用场景:当要计算某个数乘以2的n次方的时候就用左移,效率最高 //注意点:左移有可能改变数值的正负性
<a name="pAbZa"></a>
#### 右移
- `>>` 右移
- `a >> n` 把整数a的二进制位往右边移 n 位,结果为 `a / 2(n次幂) `
```c
//移出的位砍掉, 缺少的以为最高位是0就补0是1就补1(是在当前操作系统下)
printf("result = %d\n", 9 >> 1);//4
printf("result = %d\n", 9 >> 2);//2
printf("result = %d\n", 9 >> 3);//1
/*
0 : 0000 0000 0000 0000
9 : 0000 0000 0000 1001
: 0000 0000 0000 0100 //右移1位 4 = 9 / 2(1)
: 0000 0000 0000 0010 //右移2位 2 = 9 / 2(2)
: 0000 0000 0000 0001 //右移3位 1 = 9 / 2(3)
*/
//右移的应用场景:当要计算某个数除以2的N次方的时候就用右移,效率最高
拓展
输出任意一个正整数的二进制
/*
13
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 1101
0000 0000 0000 0000 0000 0000 0000 1101
1、将 13 的二进制数据向右 移动 31位,得到 13 的二进制数据的 最高位
2、将上一步得到的值 &1 得到 最高位的 值
将 13 右移 30 位 得到 第二位 二进制的数
一次类推
任何数 & 1 都是那个数
*/
void printBinary(int num) {
int offset = 31;
while (offset >= 0) {
int result = (num >> offset) & 1;//0000 0000 0000 0000 0000 0000 0000 1101
// int result = (num >> offset) ;//0000 0000 0000 0000 0000 0000 0000 13613
printf("%d",result);
offset -- ;
if ((offset+1) % 4 == 0) {
printf(" ");
}
}
printf("\n");
}
进制查表法
int num = 10;
//输出其 二进制、八进制、十六进制的值
二进制查表法
void printBinary(int value) {
//1、定义二进制的进制表
char form[2] = {'0','1'};
//2、定义可以接受二进制的数组
char binaryArr[32] = {'0'}; //32 表示 二进制数据 在 64位 操作系统里的位数
//3、定义 接受二进制数据的 索引
int index = 32;
while (value != 0) {
// 4.1 将传进来的值 & 1 得出 form 表里的对应 索引的值,。注意form 表里 顺序 一定要有序
int res = value & 1;// 1: 00000000 00000000 00000000 00000001
// 4.2 利用取出来得值到表中查询对应的结果
char c = form[res];
index -- ;//先取出来的数据 也应放在低位
binaryArr[index] = c;//赋值
// 4.移除二进制被取过的1位
value = value >> 1; //右移 1 位
}
// 4.打印结果
for (int i = index; i < 32; i++) {
printf("%c", binaryArr[i]);
}
//1010
printf("\n");
}
八进制查表法
void printOct(int value) {
// 1.定义八进制的进制表 一定要按照顺序
char form[8] = {'0','1','2','3','4','5','6','7'};
// 2.定义接受八进制的字符数组
char charValues[11] = {'0'};// 3个 二进制 => 1个八进制 ; 二进制 一共 32位,所以 八进制一共 11位
// 3.定义接受 八进制 数据的索引
int index = 11;
while (value != 0) {
// 4.1 将传进来的值 & 7 得出 form 表里 对应 索引 的值。
int res = value & 7 ; // 7 : 00000000 00000000 00000000 00000111
// 4.2 去除 对应 索引 的字符,并赋值给 低位
char determinValue = form[res];
index -- ;
charValues[index] = determinValue;
//4.3 将传进来的值 右移 三位
value = value >> 3;
}
// 4.打印结果
for (int i = index; i < 11; i++) {
printf("%c", charValues[i]);
}
//输出结果 : 12
printf("\n");
}
十六进制 查表法
void printHex(int value) {
// 1.定义十六进制的进制表 一定要按照顺序
char form[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
// 2.定义接受 十六进制 的字符数组
char charValues[4] = {'0'};// 4个 二进制 => 1个 十六进制;二进制一共 32位,所以十六进制 一共 4位
// 3.定义 接受 十六进制 字符的 索引,从低位开始
int index = 4;
while (value != 0) {
// 4.1 将传进来的value & 15,获取到 对应 form 的索引值
int res = value & 15; // 15 : 00000000 00000000 00000000 0000 1111
// 4.2 将得到的索引值 根据 form 里的元素 去除对应的字符
char destinationValue = form[res];
index -- ;
charValues[index] = destinationValue;
//4.3 将传进来的值 右移 四位
value = value >> 4;
}
// 4.打印结果
for (int i = index; i < 4; i++) {
printf("%c", charValues[i]);
}
//输出结果 : 12
printf("\n");
}
进制查表法优化
printSystem(10, 1, 1); //1010
printSystem(10, 7, 3); //12
printSystem(10, 15, 4); //
/// 打印进制的值
/// @param value value
/// @param base 按位与 的数值 2进制:1 ; 8进制:7; 16进制 : 15
/// @param offset 右移的数值 2进制:1 ; 8进制:3; 16进制 : 4
void printSystem(int value,int base,int offset) {
// 1.定义十六进制的进制表( 包括 八进制和 二进制的表) 一定要按照顺序
char form[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
// 2.定义接受 进制 的字符数组
char charValues[32] = {'0'};// 二进制一共 32位[32],3个 二进制 => 1个 八进制 [11];4个 二进制 => 1个 十六进制[4]
// 3.定义 接受 十六进制 字符的 索引,从低位开始
int index = 32;
while (value != 0) {
// 4.1 将传进来的value & base,获取到 对应 form 的索引值
int res = value & base;
// 15 : 00000000 00000000 00000000 0000 1111
// 7 : 00000000 00000000 00000000 0000 0111
// 1 : 00000000 00000000 00000000 0000 0001
// 4.2 将得到的索引值 根据 form 里的元素 去除对应的字符
char destinationValue = form[res];
index -- ;
charValues[index] = destinationValue;
//4.3 将传进来的值 右移 offset 为
value = value >> offset;
}
// 4.打印结果
for (int i = index; i < 32; i++) {
printf("%c", charValues[i]);
}
//输出结果 : 12
printf("\n");
}