简介
为什么需要反码和补码
有界/越界/溢出与取模
在数学的理论中,数字可以有无穷大,也有无穷小。现实中的计算机系统不可能表示无穷大或者无穷小的数字,都有一个上限和下限。加法加越界了就成了 取模运算。
符号位
在实际的硬件系统中,计算机 CPU 的运算器只实现了加法器,而没有实现减法器。那么计算机如何做减法呢?我们可以通过加上一个负数来达到这个目的。如何让计算机理解哪些是正数,哪些是负数呢?人们把二进制数分为有符号数(signed)和无符号数(unsigned)。如果是有符号数,那么最高位就是符号位。如果是无符号数,那么最高位就不是符号位,而是二进制数字的一部分。有些编程语言,比如 Java,它所有和数字相关的数据类型都是有符号位的;而有些编程语言,比如 C 语言,它有诸如 unsigned int 这种无符号位的数据类型。
比取模更“狠”——有符号数的溢出
对于 n 位的数字类型,符号位是 1,后面 n-1 位全是 0,我们把这种情形表示为 -2^(n-1)。n 位数字的最大的正值,其符号位为 0,剩下的 n-1 位都1,再增大一个就变为了符号位为 1,剩下的 n-1 位都为0。也就是n位 有符号最大值 加1 就变成了 n位有符号数界限范围内最小的负数——上溢出之后,又从下限开始。PS:是不是有点扑克牌的意思, A 可以作为10JQKA 的最大牌,也可以作为A23456 的最小牌。
下限 | 上限 | |
---|---|---|
n位无符号数 | 0 | 2^n-1 |
n位有符号数 | -2^(n-1) | 2^(n-1)-1 |
取模 可以将(最大值+1) 变成下限值,对于无符号数是0 ,对于有符号数是负数。
减法靠补码
原码就是我们看到的二进制的原始表示,是不是可以直接使用负数的原码来进行减法计算呢?答案是否定的,因为负数的原码并不适用于减法操作(加负数操作)
因为取模的特性,我们知道 i = i + 模数
。 那么 i-j = i-j + 模数
也是成立的,进而i-j = i + (模数 -j)
。模数 -j
即补码 可以对应到计算机的 位取反 和 加 1 操作
本质就是
- 加法器不区分 符号位和数据位
- 越界 等于 取模,对于有符号位的取模,可以使得 正数 变成负数
我们经常使用朴素贝叶斯算法 过滤垃圾短信,P(A|B)=P(A) * P(B/A) / P(B)
这个公式在数学上平淡无奇,但工程价值在于:实践中右侧数据比 左侧数据更容易获得。 cpu减法器也是类似的道理,减法器 = CPU 位取反 + 加法器
对于大多数计算机而言,通常其内部会使用补码(Two’s-complement)的格式来存放有符号整数,使用直接对应的二进制位格式来存放无符号整数,使用 IEEE-754 标准编码格式来存放浮点数,也就是小数。使用补码来存放有符号整数的一个优点是,CPU 在针对有符号数进行加减法计算时,不需要由于加数的符号性不同而采用多个底层加法电路,这样便可减轻电路设计的负担,另一方面也可以降低 CPU 的物理尺寸。补码的英文名称是 two’s-complement,可直译为“对数字 2 的补充”。PS:补码 的内涵非常多
调度系统设计精要
调度系统设计精要在计算机科学中,调度就是一种将任务(Work)分配给资源的方法。任务可能是虚拟的计算任务,例如线程、进程或者数据流,这些任务会被调度到硬件资源上执行,例如:处理器 CPU 等设备。调度模块的核心作用就是对有限的资源进行分配以实现最大化资源的利用率或者降低系统的尾延迟,调度系统面对的就是资源的需求和供给不平衡的问题。
任务 | 资源 | 描述 | |
---|---|---|---|
操作系统 | 线程 | cpu | |
Go | 协程 | cpu线程 | |
Kubernetes | pod | node | 为待运行的工作负载 Pod 绑定运行的节点 Node |
CDN的资源调度 | |||
订单调度 | |||
离线任务调度 |