diff --git a/docs/notes/01_c-basic/02_xdx/assets/37.svg b/docs/notes/01_c-basic/02_xdx/assets/37.svg index 29f26ac..99303eb 100644 --- a/docs/notes/01_c-basic/02_xdx/assets/37.svg +++ b/docs/notes/01_c-basic/02_xdx/assets/37.svg @@ -1,4 +1,4 @@ -
0
0
0
0
0
0
0
0
原码运算
0
0
0
0
0
1
1
0
6 的原码
6 + (-18)采用原码计算
-18 的原码
1
0
0
0
0
0
0
0
0
0
0
1
0
0
1
0
结果(原码)
1
0
0
0
0
0
0
0
0
0
0
1
1
0
0
0
符号位
数值位(真值)
-24
\ No newline at end of file +
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
符号位
最高位
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
num = 1;
+1 的原码
+1 的反码
+1 的补码
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
0
符号位
最高位
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
num = -1;
-1 的原码
-1 的反码
-1 的补码
\ No newline at end of file diff --git a/docs/notes/01_c-basic/02_xdx/assets/38.svg b/docs/notes/01_c-basic/02_xdx/assets/38.svg index d24337b..29f26ac 100644 --- a/docs/notes/01_c-basic/02_xdx/assets/38.svg +++ b/docs/notes/01_c-basic/02_xdx/assets/38.svg @@ -1,4 +1,4 @@ -
0
0
0
0
0
0
0
0
0
0
0
0
0
1
1
0
6 的原码(反码)
6 + (-18)采用反码计算
-18 的原码
1
0
0
0
0
0
0
0
0
0
0
1
0
0
1
0
结果(反码)
1
1
1
1
1
1
1
1
1
1
1
1
0
0
1
1
符号位
数值位(真值)
-18 的反码
1
1
1
1
1
1
1
1
1
1
1
0
1
1
0
1
1
0
0
0
0
0
0
0
0
0
0
0
1
1
0
0
结果(原码)
反码运算
-12
\ No newline at end of file +
0
0
0
0
0
0
0
0
原码运算
0
0
0
0
0
1
1
0
6 的原码
6 + (-18)采用原码计算
-18 的原码
1
0
0
0
0
0
0
0
0
0
0
1
0
0
1
0
结果(原码)
1
0
0
0
0
0
0
0
0
0
0
1
1
0
0
0
符号位
数值位(真值)
-24
\ No newline at end of file diff --git a/docs/notes/01_c-basic/02_xdx/assets/39.svg b/docs/notes/01_c-basic/02_xdx/assets/39.svg index 0bbf08a..d24337b 100644 --- a/docs/notes/01_c-basic/02_xdx/assets/39.svg +++ b/docs/notes/01_c-basic/02_xdx/assets/39.svg @@ -1,4 +1,4 @@ -
0
0
0
0
0
0
0
0
0
0
0
1
0
0
1
0
18 的原码(反码)
18 + (-6)采用反码计算
-6 的原码
1
0
0
0
0
0
0
0
0
0
0
0
0
1
1
0
结果(反码)
0
0
0
0
0
0
0
0
0
0
0
0
1
0
1
1
符号位
数值位(真值)
-6 的反码
1
1
1
1
1
1
1
1
1
1
1
1
1
0
0
1
0
0
0
0
0
0
0
0
0
0
0
0
1
0
1
1
结果(原码)
反码运算
11
1
溢出,丢弃
\ No newline at end of file +
0
0
0
0
0
0
0
0
0
0
0
0
0
1
1
0
6 的原码(反码)
6 + (-18)采用反码计算
-18 的原码
1
0
0
0
0
0
0
0
0
0
0
1
0
0
1
0
结果(反码)
1
1
1
1
1
1
1
1
1
1
1
1
0
0
1
1
符号位
数值位(真值)
-18 的反码
1
1
1
1
1
1
1
1
1
1
1
0
1
1
0
1
1
0
0
0
0
0
0
0
0
0
0
0
1
1
0
0
结果(原码)
反码运算
-12
\ No newline at end of file diff --git a/docs/notes/01_c-basic/02_xdx/assets/40.svg b/docs/notes/01_c-basic/02_xdx/assets/40.svg index f31c8c0..0bbf08a 100644 --- a/docs/notes/01_c-basic/02_xdx/assets/40.svg +++ b/docs/notes/01_c-basic/02_xdx/assets/40.svg @@ -1,4 +1,4 @@ -
0
0
0
0
0
0
0
0
0
0
0
0
0
1
1
0
6 的原码(反码,补码)
6 + (-18)采用补码计算
-18 的原码
1
0
0
0
0
0
0
0
0
0
0
1
0
0
1
0
结果(补码)
1
1
1
1
1
1
1
1
1
1
1
1
0
1
0
0
符号位
数值位(真值)
-18 的反码
1
1
1
1
1
1
1
1
1
1
1
0
1
1
0
1
1
1
1
1
1
1
1
1
1
1
1
1
0
0
1
1
结果(反码)
补码运算
-12
1
1
1
1
1
1
1
1
1
1
1
0
1
1
1
0
-18 的补码
结果(原码)
1
0
0
0
0
0
0
0
0
0
0
0
1
1
0
0
\ No newline at end of file +
0
0
0
0
0
0
0
0
0
0
0
1
0
0
1
0
18 的原码(反码)
18 + (-6)采用反码计算
-6 的原码
1
0
0
0
0
0
0
0
0
0
0
0
0
1
1
0
结果(反码)
0
0
0
0
0
0
0
0
0
0
0
0
1
0
1
1
符号位
数值位(真值)
-6 的反码
1
1
1
1
1
1
1
1
1
1
1
1
1
0
0
1
0
0
0
0
0
0
0
0
0
0
0
0
1
0
1
1
结果(原码)
反码运算
11
1
溢出,丢弃
\ No newline at end of file diff --git a/docs/notes/01_c-basic/02_xdx/assets/41.svg b/docs/notes/01_c-basic/02_xdx/assets/41.svg index 2548443..f31c8c0 100644 --- a/docs/notes/01_c-basic/02_xdx/assets/41.svg +++ b/docs/notes/01_c-basic/02_xdx/assets/41.svg @@ -1,4 +1,4 @@ -
0
0
0
0
0
0
0
0
0
0
0
1
0
0
1
0
18 的原码(反码,补码)
18 + (-6)采用补码计算
-6 的原码
1
0
0
0
0
0
0
0
0
0
0
0
0
1
1
0
结果(补码)
0
0
0
0
0
0
0
0
0
0
0
0
1
1
0
0
符号位
数值位(真值)
-6 的反码
1
1
1
1
1
1
1
1
1
1
1
1
1
0
0
1
0
0
0
0
0
0
0
0
0
0
0
0
1
1
0
0
结果(反码)
补码运算
12
1
溢出,丢弃
1
1
1
1
1
1
1
1
1
1
1
1
1
0
1
0
-6 的补码
结果(原码)
0
0
0
0
0
0
0
0
0
0
0
0
1
1
0
0
\ No newline at end of file +
0
0
0
0
0
0
0
0
0
0
0
0
0
1
1
0
6 的原码(反码,补码)
6 + (-18)采用补码计算
-18 的原码
1
0
0
0
0
0
0
0
0
0
0
1
0
0
1
0
结果(补码)
1
1
1
1
1
1
1
1
1
1
1
1
0
1
0
0
符号位
数值位(真值)
-18 的反码
1
1
1
1
1
1
1
1
1
1
1
0
1
1
0
1
1
1
1
1
1
1
1
1
1
1
1
1
0
0
1
1
结果(反码)
补码运算
-12
1
1
1
1
1
1
1
1
1
1
1
0
1
1
1
0
-18 的补码
结果(原码)
1
0
0
0
0
0
0
0
0
0
0
0
1
1
0
0
\ No newline at end of file diff --git a/docs/notes/01_c-basic/02_xdx/assets/42.svg b/docs/notes/01_c-basic/02_xdx/assets/42.svg new file mode 100644 index 0000000..2548443 --- /dev/null +++ b/docs/notes/01_c-basic/02_xdx/assets/42.svg @@ -0,0 +1,4 @@ + + + +
0
0
0
0
0
0
0
0
0
0
0
1
0
0
1
0
18 的原码(反码,补码)
18 + (-6)采用补码计算
-6 的原码
1
0
0
0
0
0
0
0
0
0
0
0
0
1
1
0
结果(补码)
0
0
0
0
0
0
0
0
0
0
0
0
1
1
0
0
符号位
数值位(真值)
-6 的反码
1
1
1
1
1
1
1
1
1
1
1
1
1
0
0
1
0
0
0
0
0
0
0
0
0
0
0
0
1
1
0
0
结果(反码)
补码运算
12
1
溢出,丢弃
1
1
1
1
1
1
1
1
1
1
1
1
1
0
1
0
-6 的补码
结果(原码)
0
0
0
0
0
0
0
0
0
0
0
0
1
1
0
0
\ No newline at end of file diff --git a/docs/notes/01_c-basic/02_xdx/index.md b/docs/notes/01_c-basic/02_xdx/index.md index 6ddcf95..a22d35e 100644 --- a/docs/notes/01_c-basic/02_xdx/index.md +++ b/docs/notes/01_c-basic/02_xdx/index.md @@ -166,9 +166,11 @@ float m=3.14,n=4.14; > [!NOTE] > -> * ① C 语言有多少种数据类型,每种数据类型长度是多少、该如何使用,这是每一位 C 程序员都必须要掌握的。当然,不必担心,后续还会一一讲解的。 +> C 语言有多少种数据类型,每种数据类型长度是多少、该如何使用,这是每一位 C 程序员都必须要掌握的。当然,不必担心,后续还会一一讲解的。 + +> [!IMPORTANT] > -> * ② 需要说明的是,数据类型只在定义变量时指明,而且必须指明;使用变量时无需再指明,因为此时的数据类型已经确定了。 +> 数据类型只需要在定义变量时指明,而且必须指明;使用变量时无需再指明,因为此时的数据类型已经确定了。 ## 1.5 从计算机底层看变量 @@ -1153,11 +1155,11 @@ int main() { ### 3.5.1 概述 -* 机器数:一个数在计算机的存储形式是二进制,我们称这些二进制数为机器数。机器数可以是有符号的,用机器数的最高位来存放符号位,0 表示正数,1 表示负数。 +* 机器数:一个数在计算机的存储形式是二进制,我们称这些二进制数为机器数。机器数可以是有符号的,用机器数的最高位来存放符号位,`0` 表示正数,`1` 表示负数。 > [!IMPORTANT] > -> 这里讨论的适用于`符号位`的整数,如:int 等;而不适用于`无符号位`的整数,即:unsinged int 等。 +> 这里讨论的适用于`有符号位`的整数,如:int 等;而不适用于`无符号位`的整数,即:unsinged int 等。 ![](./assets/33.svg) @@ -1165,7 +1167,7 @@ int main() { > [!IMPORTANT] > -> 这里讨论的适用于`符号位`的整数,如:int 等;而不适用于`无符号位`的整数,即:unsinged int 等。 +> 这里讨论的适用于`有符号位`的整数,如:int 等;而不适用于`无符号位`的整数,即:unsinged int 等。 ![](./assets/34.svg) @@ -1175,23 +1177,23 @@ int main() { * 规则: * 正数的`原码`是它本身对应的二进制数,符号位是 0 。 * 负数的`原码`是它本身绝对值对应的二进制数,但是符号位是 1 。 -* +1 的原码,使用 8 位二进数来表示,就是: +* +1 的原码,使用 `16` 位二进数来表示,就是: -| 十进制数 | 原码(8位二进制数) | -| -------- | ------------------- | -| +1 | `0`000 0001 | +| 十进制数 | 原码(16位二进制数) | +| -------- | --------------------- | +| +1 | `0`000 0000 0000 0001 | -* -1 的原码,使用 8 位二进数来表示,就是: +* -1 的原码,使用 `16` 位二进数来表示,就是: -| 十进制数 | 原码(8位二进制数) | -| -------- | ------------------- | -| -1 | `1`000 0001 | +| 十进制数 | 原码(16位二进制数) | +| -------- | --------------------- | +| -1 | `1`000 0000 0000 0001 | > [!IMPORTANT] > > 总结: > -> * ① 按照原码的规则,会出现 `+0` 和 `-0` 的情况,即:`0`000 0000(+0)、`1`000 0000(-0),显然不符合实际情况。 +> * ① 按照原码的规则,会出现 `+0` 和 `-0` 的情况,即:`0`000 0000 0000 0001(+0)、`1`000 0000 0000 0001(-0),显然不符合实际情况。 > * ② 所以,计算机底层虽然存储和计算的都是二进数,但显然不是原码。 ### 3.5.3 反码 @@ -1201,23 +1203,23 @@ int main() { * 正数的反码和它的原码相同。 * 负数的反码是在其原码的基础上,符号位不变,其余各位取反。 -* +1 的反码,使用 8 位二进数来表示,就是: +* +1 的反码,使用 `16` 位二进数来表示,就是: -| 十进制数 | 原码(8位二进制数) | 反码(8位二进制数) | -| -------- | ------------------- | ------------------- | -| +1 | `0`000 0001 | `0`000 0001 | +| 十进制数 | 原码(16位二进制数) | 反码(16位二进制数) | +| -------- | --------------------- | --------------------- | +| +1 | `0`000 0000 0000 0001 | `0`000 0000 0000 0001 | -* -1 的反码,使用 8 位二进数来表示,就是: +* -1 的反码,使用 `16` 位二进数来表示,就是: -| 十进制数 | 原码(8位二进制数) | 反码(8位二进制数) | -| -------- | ------------------- | ------------------- | -| -1 | `1`000 0001 | `1`111 1110 | +| 十进制数 | 原码(16位二进制数) | 反码(16位二进制数) | +| -------- | --------------------- | --------------------- | +| -1 | `1`000 0000 0000 0001 | `1`111 1111 1111 1110 | > [!IMPORTANT] > > 总结: > -> * ① 按照反码的规则,如果是 `+0`,对应的原码是 `0`000 0000;那么,其反码还是 `0`000 0000 ;如果是 `-0`,对应的原码是 `1`000 0000,其反码是 `1`111 1111,显然不符合实际情况。 +> * ① 按照反码的规则,如果是 `+0`,对应的原码是 `0`000 0000 0000 0000;那么,其反码还是 `0`000 0000 ;如果是 `-0`,对应的原码是 `1`000 0000 0000 0000,其反码是 `1`111 1111 1111 1111,显然不符合实际情况。 > * ② 所以,计算机底层虽然存储和计算的都是二进数,但显然不是反码。 ### 3.5.4 补码 @@ -1226,17 +1228,17 @@ int main() { * 正数的补码和它的原码相同。 * 负数的补码是在其反码的基础上 + 1 。 -* +1 的补码,使用 8 位二进数来表示,就是: +* +1 的补码,使用 `16` 位二进数来表示,就是: -| 十进制数 | 原码(8位二进制数) | 反码(8位二进制数) | 补码(8位二进制数) | -| -------- | ------------------- | ------------------- | ------------------- | -| +1 | `0`000 0001 | `0`000 0001 | `0`000 0001 | +| 十进制数 | 原码(16位二进制数) | 反码(16位二进制数) | 补码(16位二进制数) | +| -------- | --------------------- | -------------------- | -------------------- | +| +1 | `0`000 0000 0000 0001 | 0000 0000 0000 0001 | 0000 0000 0000 0001 | -* -1 的补码,使用 8 位二进数来表示,就是: +* -1 的补码,使用 `16` 位二进数来表示,就是: -| 十进制数 | 原码(8位二进制数) | 反码(8位二进制数) | 补码(8位二进制数) | -| -------- | ------------------- | ------------------- | ------------------- | -| -1 | `1`000 0001 | `1`111 1110 | `1`111 1111 | +| 十进制数 | 原码(16位二进制数) | 反码(16位二进制数) | 补码(16位二进制数) | +| -------- | --------------------- | --------------------- | --------------------- | +| -1 | `1`000 0000 0000 0001 | `1`111 1111 1111 1110 | `1`111 1111 1111 1111 | * 如果 `0` ,按照 `+0` 的情况进行处理,如下所示: @@ -1246,19 +1248,25 @@ int main() { ![](./assets/36.svg) +* `+1` 和 `-1` 的`原码`和`补码`的转换过程,如下所示: + +![](./assets/37.svg) + > [!IMPORTANT] > > 总结: > > * ① 补码表示法解决了`原码`和`反码`存在的`两种`零(`+0` 和 `-0`)的问题,即:在补码表示法中,只有`一个`零,即 `0000 0000`。 > * ②补码使得`加法运算`和`减法运算`可以统一处理,通过将减法运算`转换`为加法运算,可以简化硬件设计,提高了运算效率。 -> * ③ 计算机底层`存储`和`计算`的都是`二进数的补码`。换言之,当读取整数的时候,需要采用逆向的转换,即:将补码转换为原码。正数的原码、反码、补码都是一样的,三码合一。负数的补码转换为原码的方法就是先减去 `1` ,得到反码,再按位取反,得到原码。 +> * ③ 计算机底层`存储`和`计算`的都是`二进数的补码`。换言之,当`读取`整数的时候,需要采用`逆向`的转换,即:将补码转换为原码。正数的原码、反码、补码都是一样的,三码合一。负数的补码转换为原码的方法就是先减去 `1` ,得到反码,再按位取反,得到原码。 ### 3.5.5 总结 -* ① 正数的原码、反码和补码都是一样的,三码合一。 -* ② 负数的反码是在其原码的基础上,按位取反(0 变 1 ,1 变 0 ),符号位不变;负数的补码是其反码 + 1 。 -* ③ 0 的补码是 0 。 +* ① 计算机底层`存储`和`计算`的都是`二进数的补码`。换言之,当`读取`整数的时候,需要采用`逆向`的转换,即:将补码转换为原码。 +* ② 正数的原码、反码和补码都是一样的,三码合一。 +* ③ 负数的反码是在其原码的基础上,按位取反(0 变 1 ,1 变 0 ),符号位不变;负数的补码是其反码 + 1 。 +* ④ 0 的补码是 0 。 +* ⑤ 负数的补码转换为原码的方法就是先减去 `1` ,得到反码,再按位取反,得到原码。 ## 3.6 计算机底层为什么使用补码? @@ -1267,7 +1275,7 @@ int main() { * 此外,加法和减法也可以合并为一种运算,即:加法运算。换言之,减去一个数就相当于加上这个数的相反数,如:`5 - 3` 相当于 `5 +(-3)`,`10 -(-9)`相当于 `10 + 9` 。 * 如果能够实现上述的两个目标,那么只需要设计一种简单的、不用区分符号位和数值位的加法电路,就能同时实现加法运算和减法运算,而且非常高效。其实,这两个目标已经实现了,真正的计算机的硬件电路就是这样设计的。 -* 但是,简化硬件电路是有代价的,这个代价就是有符号数在存储和读取的时候都要继续转换。这也是对于有符号数的运算来说,计算机底层为什么使用`补码`的原因所在。 +* 但是,简化硬件电路是有代价的,这个代价就是`有符号数`在存储和读取的时候都要继续转换。这也是对于有符号数的运算来说,计算机底层为什么使用`补码`的原因所在。 ## 3.7 补码到底是如何简化硬件电路的? @@ -1277,7 +1285,7 @@ int main() { > > 直接使用原码表示整数,让符号位也参与运算,那么对于减法来说,结果显然是不正确的。 -![](./assets/37.svg) +![](./assets/38.svg) * 于是,人们开始继续探索,不断试错,终于设计出了`反码`,如下所示: @@ -1285,7 +1293,7 @@ int main() { > > 直接使用反码表示整数,让符号位也参与运算,对于 6 +(-18)来说,结果貌似正确。 -![](./assets/38.svg) +![](./assets/39.svg) * 如果我们将`被减数`和`减数`对调一下,即:计算 `18 - 6` 的结果,也就是 `18 +(-6)`的结果,继续采用`反码`来进行运算,如下所示: @@ -1294,15 +1302,15 @@ int main() { > * ① 6 - 18,即:6+(-18),如果采用`反码`计算,结果是正确的;但是,18 - 6,即:18 +(-6),如果采用`反码`计算,结果相差 1 。 > * ② 可以推断:如果按照`反码`来计算,小数 - 大数,结果正确;而大数 - 小数,结果相差 1 。 -![](./assets/39.svg) +![](./assets/40.svg) * 对于这个相差的 `1` 必须进行纠正,但是又不能影响`小数-大数`的结果。于是,人们又绞尽脑汁设计出了`补码`,给`反码`打了一个`“补丁”`,终于把相差的 `1` 给纠正过来了。那么,`6 - 18` 按照`补码`的运算过程,如下所示: -![](./assets/40.svg) +![](./assets/41.svg) * 那么,`18 - 6` 按照`补码`的运算过程,如下所示: -![](./assets/41.svg) +![](./assets/42.svg) > [!IMPORTANT] >