From 1dc17dfc8c7b843db2cf2ec2f04a3cb8d72ff01c Mon Sep 17 00:00:00 2001 From: ClovertaTheTrilobita Date: Thu, 10 Sep 2026 16:25:52 +0800 Subject: [PATCH] added draft --- src/blog/zh/arithmetic-in-computer.md | 210 ++++++++++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 src/blog/zh/arithmetic-in-computer.md diff --git a/src/blog/zh/arithmetic-in-computer.md b/src/blog/zh/arithmetic-in-computer.md new file mode 100644 index 0000000..6911bbf --- /dev/null +++ b/src/blog/zh/arithmetic-in-computer.md @@ -0,0 +1,210 @@ +--- +title: "如何教会计算机算术??加减篇" +pubDate: 2026-08-04 +description: '欢迎来到琪露诺的奇妙数学教室,让我们从……加减法开始吧!' +author: "三叶" +image: + url: "https://files.seeusercontent.com/2026/08/04/fkE6/pasted-image-1785836458506.webp" + alt: "bintree" +tags: ["学习笔记", "计算机组成原理"] +--- + +1+1等于几? + +这个问题困扰了人们很多年。 + +有人说,一加一等于1,因为两个麦芽糖黏在一起还是一个麦芽糖。 + +有人说,一加一等于2,因为双击`计算器.exe`,输入1+1,输出结果是2。 + +有人说…… + +
+ +……我编不下去了。 + +那么各位小朋友大朋友早上中午晚上好。今天我们要来教会一台计算机如何进行加减法。 + +就是这么简单。 + +咦?其实不简单吗? + +## 零、让我们从零开始 + +假设你的老妈在厨房大吼:“崽啊,快来吃饭!菜都要凉辣!”但是你此时没有办法迅速赶到餐桌,因为你正在忙着偷偷用老妈的支付宝购买*那个游戏6*!你的手边只有餐厅吊灯的神秘开关,你要怎么像老妈传达信息呢? + +很简单!控制灯的亮起即可!我们将点亮的灯泡视为`True`(或者更简单地:`1`),熄灭的灯泡视为`False`(或者`0`),这样,你就可以高效地传递信息! + +随后你毅然决然地关闭了餐厅的灯,坏结局,你的老妈并不知道高深莫测的计算机组成原理,从她的视角来看…… + +小崽子又欠揍了(抄起衣服架子)。 + +怎么办,世界末日就在眼前!但是别慌,因为老妈还有10秒才会破门而入,在这么充裕的时间内足以我们开启下一章节了。 + +## 一、数字在计算机中的表达 + +### 1. 二进制 + +现在,想象你手中拿的是一根电线,没错,就是连着餐厅吊灯的那条电线,回想一下,你是怎么通过电线进行信号传输的呢? + +那就是:通电代表`1`,未通电代表`0`。 + +但是这只能表达两种状态啊,这个世界不是非黑即白的,如果我们需要表达四种状态怎么办? + +简单,再加上一根电线。 + +现在我们可以通过控制两根电线来表达`00`,`01`,`10`,`11`这四种状态,那给它们起个编号吧! + +`00`代表`0`;`01`代表`1`;`10`代表`01+01`,进一位,是`2`;`11`就是`10+01`是`3`; + +没错,这就是**二进制**表示数据。 + +在计算机中,我们普遍使用二进制来计算基础运算,这其实是个很显而易见的道理,如果使用十进制,我们需要针对十种不同的状态设计十个不同的电路,而二进制就很简单了,用一根简单的电线,通电代表1,没通电代表0。 + +#### 二进制的转换 + +那么假如给你一串随机的**二进制数**:`010110`,我们怎么知道它对应的是多少呢? + +我们先来看看十进制数。 + +随便取一个十进制数:`21367`,它可以很直观地被拆成 +$$ +2\times10^4+1\times10^3+3\times10^2+6\times10^1+7\times10^0=21367 +$$ +那么很直观地我们能想到,对于r进制的数`21367`,我们可以表达成 +$$ +2\times r^4+1\times r^3+3\times r^2+6\times r^1+7\times r^0=21367 +$$ +更通用地,对于r进制的数$K_nK_{n-1}K_{n-2}...K_1K_0$,可以表达为 +$$ +K_nr^n+K_{n-1}r^{n-1}+K_{n-2}r^{n-2}+...+K_1r^1+K_0r^0 +$$ +感觉晕头转向?我们直接拿这个**二进制数**`010110`为例: +$$ +010110 = 0\times2^5+1\times2^4+0\times2^3+1\times2^2+1\times2^1+0\times2^0 +$$ +于是它所对应的十进制数就是:$2^4+2^2+2^1=16+4+2=22$ + +怎么样,是不是很简单? + +#### 十六进制数 + +你一定听说过这么个名词:**32位操作系统**和**64位操作系统**。 + +没错,**32位操作系统**代表着,对于`int`整形的变量,一共有32个**比特**用来存储这么一个数。 + +也就是说,二进制数的长度最长可以有32位。 + +好多!那么程序员在调试的时候总不能用手指头指着屏幕上的0和1一个一个数过去吧? + +于是我们在此引入**十六进制数**。 + +我们规定,$A$代表$10$,$B$代表$11$,$C$代表$12$,以此类推,$F$代表$15$。 + +那么完整的16进制个位数便是:$123456789ABCDEF$ + +你惊人的注意力一定注意到了,这刚好对应**4位2进制数**! + +于是,我们可以将一个很长的**二进制数**`01101011`聚合为两个**十六进制数**`6B` + +### 2. 二进制数的编码表示 + +#### 机器数 + +现在想必你已经能够熟练的使用二进制数进行加减法了,那我们来想想这么一个情况。 + +假设一个计算机的寄存器中,只有8个位置,即只能存8个0或1,我们该如何存正数和负数呢? + +很简单,拿出第一个位置,规定: + +第一个位置存0,代表这是一个正数;存1,代表这是一个负数。 + +那么我们能表达的最小数字便是:`11111111`即$-127$ + +最大数是:`01111111`即`127` + +但是接下来的问题头疼了,我们怎么对他们进行运算? + +#### 原码vs补码 + +我们知道,为了尽可能简化CPU内部部件以实现资源的最大化利用,我们的CPU基础部件只能进行加法运算。 + +那么对于两个正数,我们很好计算,比如$1+1$: +$$ +1+1=0000\ 0001+0000\ 0001 = 0000\ 0010 +$$ +我们尝试把它变大一点: +$$ +127+3=0111\ 1111+0000\ 0011=1 \ 0000\ 0010 +$$ +多出来了一位!然而很可惜,我们计算机只能存8个bit,所以多出来的`1`我们只能忍痛丢掉,计算结果就是 +$$ +0000\ 0010 = 2 +$$ +这就是计算过程中发生了溢出。导致计算结果和实际结果不一致。 + +但是你又用惊人的注意力发现了:计算结果是2……这刚好就是……?! +$$ +130\bmod 128=2 +$$ +没错,我们这样子计算,刚好就是在将计算结果对$128$进行[模运算](https://zh.wikipedia.org/zh-cn/%E6%A8%A1%E7%AE%97%E6%95%B8)! + +那我们是不是可以巧妙地利用这一特性,通过加法来实现减法呢?! + +比如说我们有两个数:$50$和$30$,我们需要计算$50-30$ + +既然在这个计算机中,我们计算的结果都是 +$$ +(A+B) \bmod 128 +$$ +那$50-30$就可以看作 +$$ +\begin{aligned} +[50+(-30)]\bmod 128 +&=[50+(-30\bmod 128)]\bmod 128\\ +&=[50+98]\bmod 128\\ +&=148\bmod 128\\ +&=20 +\end{aligned} +$$ +哇!天才!台下观众欣喜若狂! + +对于二进制数来说,我们怎么表达它呢? + +我们在此引入**补码**的概念。 + +$-30$的二进制原码是:`1001 1110` + +现在我们除了符号位以外,全部给他取反得到反码:`1110 0001` + +再给它末位加上一,就可以得到**补码**:`1110 0010`。 + +对于正数,我们则规定**补码就是其本身**。 + +那么对于$50-30$,我们可以在运算时使用$[50]_{补}+[-30]_{补}$,对于这个计算就变成了 +$$ +0011 \ 0010 + 1110\ 0010 = 1\ 0001\ 0100 +$$ +丢弃溢出的最高位,我们得到`0001 0100`也就是$20$。 + +#### 补码的其他好处 + +如果使用原码,我们会发现一个很尴尬的情况:0有两种表示方法。 + +即`1000 0000`表示`-0`,`0000 0000`表示`+0`。 + +但在补码中,我们可以规定`1000 0000`表示$-128$,这样就比原码能多存一个数字!表示范围也扩展为$-128$~$127$。 + +#### 有符号数vs无符号数 + +以上的带符号的数我们称为**有符号数**。它们在计算机中以**补码**形式存储。 + +但是对于一些其他需求,我们不需要带符号的数,那么我们在计算机中就直接以**原码**的形式存储,并且**不带符号位**。 + +例如在一个8位操作系统中,你使用 + +```C +unsigned int i = 129; +``` + +那么它存的就直接是`1000 00001` \ No newline at end of file