简介
关于进制,我们平时接触的最多的就是十进制,用于计数。除了常用十进制,比较常用的还有跟时间相关的进制,比如七进制(一周七天)、十二进制(一年12个月)、二十四进制(一天24小时)、三十进制(一月30天)、六十进制(一小时60分钟)等。
进制就是进位计数制。 对于任何一种进制(X进制),每一位置上的数运算时都是逢X进一位。 十进制是逢十进一(10n),十六进制是逢十六进一(16n),二进制就是逢二进一(2n),以此类推,x进制就是逢x进位(xn)。
在计算机中,最常用的是二进制,这是因为组成计算机系统的逻辑电路通常只有开
和关
这两个状态。使用二进制可以方便简单的表达这两个状态,0和1与开和关对应。另外,二进制也非常适合逻辑运算。逻辑运算中的真和假刚好可以与二进制中的0和1对应。逻辑运算中的加法(或)、乘法(与)以及否定(非)都可以通过0和1的加法、乘法和减法来实现。所以说,没有二进制就没有如今的计算机系统。
如果用我们熟悉的十进制来设计具有10种状态的电路,情况会变得非常复杂,判断状态出错的概率大大提高。
根据等价性原则所有复杂的计算都可以等价成很多加减乘除运算,进而等价成开关电路控制的二进制逻辑运算。
由于二进制数书写冗长、易错、难记,而十六进制数或八进制数都是2的倍数,与二进制数转换简单,所以一般用十六进制数或八进制数作为二进制数的缩写。比如:二进制数1010010111001011对应的十六进制数为A5CD,容易读写。
现代高级语言中,为了方便人类的读写,数字一般用十进制来表示的,语言底层自动做了二进制的转换。
比如声明一个变量
var Number int32 = 666 //十进制
一般不这样声明(当然也可以)
var Number int32 = 1010011010 //二进制
var Number int32 = 01232 //八进制。以0开头,表示八进制
var Number int32 = 0x29a //十六进制。以0x开头,表示十六进制
位(bit)、字节(byte)、字(word)
位、字节、字是计算机中的基本概念,跟二进制息息相关。
位(bit)
:音译为比特,简记为b,表示二进制位(每个0或1就是一个位)。位是数据存储的最小单位。计算机中的CPU位数指的是CPU一次能处理的最大位数。例如64位计算机的CPU一个机器周期内可以处理64位二进制数据的计算。
、字节(byte)
:字节习惯上用大写的B
表示。字节是计算机中数据处理的基本单位。计算机中以字节为单位存储和解释信息,规定一个字节由八个二进制位构成,即1个字节等于8个比特(1Byte=8bit)
。八位二进制数最小为00000000,最大为11111111;通常1个字节可以存入一个ASCII码,2个字节可以存放一个汉字国标码。
字(word)
:计算机进行数据处理时,一次存取、加工和传送的数据长度称为字(word)。一个字通常由一个或多个(一般是字节的整数位)字节构成。例如286微机的字由2个字节组成,它的字长为16;486微机的字由4个字节组成,它的字长为32位机。计算机的字长决定了其CPU一次操作处理实际位数的多少,由此可见计算机的字长越大,其性能越优越。
进制转换
1、十进制与其他进制之间转换
十进制转换为其他进制
除基数取余,逆序排列
如十进制转换为二进制:除2取余,逆序排列
具体做法是:用2整除十进制整数,可以得到一个商和余数;再用2去除商,又会得到一个商和余数,如此进行,直到商为小于1时为止,然后把先得到的余数作为二进制数的低位有效位,后得到的余数作为二进制数的高位有效位,依次排列起来
其他进制数转换为十进制数
按权相加
二进制数11010010对应的十进制数为
1x2^7 + 1x2^6 + 0x2^5 + 1x2^4 + 0x2^3 + 0x2^2 + 1x2^1 + 0x2^0 = 128+64+0+16+0+0+2+0 = 210
十六进制数d2对应的十进制数为
13x16^1 + 2x16^0 = 208+2 = 210
2、二进制与十六进制、八进制之间转换
二进制转换为十六进制或八进制
二进制转换为八进制或十六进制规则一样,只是分组不同
以二进制转换为十六进制为例(4位并1位)
从右往左,按4位并1位方式,把二进制数分成权位不同的组(最右边的组为第1位),高位不足部分补0。
各组4位二进制数加权展开求和。
得到十六进制数。
十六进制或八进制转换为二进制
八进制或十六进制转换为二进制规则一样,只是分组不同
比如十六进制转换为二进制(1位拆4位)
1位拆4位,每个十六进制数分别通过除2取余法,得到二进制数,每个十六进制数对应4个二进制数,不足时在高位补零。最终得到二进制数。
二进制的运算
根据等价性原则所有复杂的计算都可以等价成很多加减乘除运算,进而等价成开关电路控制的二进制逻辑运算。
二进制的运算分为算术运算、逻辑运算和位运算。
二进制的算术运算
算术运算即加(+)
、减(-)
、乘(*)
、除(/)
和取余(%)
这五种运算,规则与代数运算规则相同。
在计算机中,加法运算是算术运算中最基本、最核心的运算,其他的运算都可以转换为加法运算和位移运算来完成。这样计算机中只需要一个加法器就可以了而不需要单独设计一个减法器,极大的简化了计算机的设计复杂度。
为了使其他运算可以转换为加法运算,计算机系统中的数值一律用补码来表示和存储,所以这里的算术运算也就是补码的算术运算。使用补码还有另外的两大好处,一个可以将符号位和数值域统一处理,降低了CPU指令的设计难度(不用单独判断符号位);另一个可以统一 +0 和 -0 的表示,所以补码的表示范围比原码和反码表示的范围都要大,对于一个8位的有符号二进制数,用补码能够表示的范围为-128127,而用原码能够表示的范围为-127127。此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。
同一个二进制数,表示的有符号数和无符号数是不同的。编程语言中需要程序员指定有符号数还是无符号数。比如int8表示八位有符号数,uint8表示八位无符号数。
加法的运算规则为:先对位,后相加。逢二进一
0+0=0 1+1=10
0+1=1 1+0=1
1 1 1 0
+ 0 1 1 0
----------------
1 0 1 0 0
减法运算直接转换为加法运算
乘法运算转换为加法运算和位移运算
除法运算转换为减法运算和位移运算
补码相关知识补充
计算机中的符号数有三种表示方法,即原码、反码和补码。三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位,三种表示方法各不相同。
理解补码必须了解模
的概念
模
是指一个计量系统的计数范围,实质上是计量器产生“溢出”的量,它的值在计量器上表示不出来,计量器上只能表示出模的余数。任何有模的计量器,均可化减法为加法运算。
理解模的一个典型例子是时钟。假设当前时针指向10点,而准确时间是6点,调整时间可有以下两种拨法:一种是倒拨4小时,即:10-4=6;另一种是顺拨8小时:10+8=12+6=6。拨到12的时候,其实是相当于“溢出”了,舍弃。在以12模的系统中,加8和减4效果是一样的,因此减4运算可以用加8来代替。对“模”而言,8和4互为补数。
计算机中n位的计量范围是0~2^(n)-1
,模为2^(n)
。如8位无符号二进制数模为256,计量范围为0~255
有符号的整数 | 原码 | 反码 | 补码 | 转换规则 |
---|---|---|---|---|
127 | 01111111 | 01111111 | 01111111 | 正整数的原码、反码、补码完全一样,即符号位固定为0,数值位相同 |
-127 | 11111111 | 10000000 | 10000001 | 负整数的符号位固定为1,原码数值位全部取反得到反码,然后加1,得到补码 |
二进制的逻辑运算
二进制的逻辑运算其实用的就是布尔的逻辑运算。19世纪末由英国数学家布尔发明。
二进制数的逻辑运算包括逻辑加法(“或”运算)、逻辑乘法(“与”运算)、逻辑否定(“非”运算)和逻辑“异或”运算。
逻辑运算 | 数学符号 | 计算机符号 | 规则 | 示例 |
---|---|---|---|---|
或 | ∨ | || | 一真即真,全假才假 | 0∨0=0,0∨1=1,1∨0=1,1∨1=1 |
与 | ∧ | && | 全真才真,一假全假 | 0∧1=0,1∧0=0,1∧1=1 |
非 | ┐ | ! | 取反 | ┐0=1,┐1=0 |
异或 | ⊕ | xor | 异1同0 | 0⊕0=0,0⊕1=1,1⊕0=1,1⊕1=0 |
二进制的位运算
位运算就是直接对整数在内存中的二进制位进行操作。常见的二进制位运算包括移位运算(左移、右移)和按位逻辑运算(按位或、按位与、按位异或)。
移位运算
移位运算是最有效的计算乘/除乘法的运算之一。分为左移和右移两种。
左移
m<<n //把m左移n位。丢弃最左边的n位;最右边补n个0。
//八位二进制数
00100011(35) << 1 = 01000110(70)
00100011(35) << 2 = 10001100(140)
当数值未溢出时,二进制左移一位,就是将数字翻倍
00100011(35) << 3 =00011000(24)
当数值左移溢出时,无以上规律
右移
m>>n //把m右移n位。丢弃最右边的n位;无符号数最左边补n个0,有符号数最左边某些机器用n个符号位填补(即“算术移位”),而另一些机器则用n个0填补(即“逻辑移位”)。对于有符号数,如果为正数则最左边补n个0,如果为负数,就分情况,有的补n个0有的补n个1。
00000101(5) >> 1 = 00000010(2)
11111011(-5) >> 2 = 11111110(-2)
二进制右移一位,就是将数字除以2得到的整数商
按位逻辑运算
位运算 | 数学符号 | 计算机符号 | 规则 | 示例 |
---|---|---|---|---|
按位或 | or | | | 每一位,都符合一真即真,全假才假 | 11010(26) or 0110(6) = 11110(30) |
按位与 | and | & | 每一位,都符合全真才真,一假全假 | 11010(26) and 0110(6) = 11110(2) |
按位异或 | xor | ∧ | 每一位,都符合异1同0 | 11010(26) xor 0110(6) = 11100(28) |
按位逻辑运算用途
按位或
对一个二进制数的某些位重置为1。二进制数要置为1的位分别跟1相或,即可置为1。将10101010后四位重置为1:10101010 | 0000 1111 = 10101111
按位与
1、清零。如果想将一个单元清零,即使其全部二进制位为0,只要跟一个各位都为零的数值相与,结果为零。将11010清零:11010 & 00000 = 00000
2、取一个数中的指定位。二进制数要取的位分别跟1相与,即可得到指定位。取10101110的低四位:10101110 & 0000 1111 = 0000 1110
3、保留指定位。二进制数要保留的位跟1相与,跟取一个数中指定位一样。保留10101110的2、5、6位:10101110 & 0011 0010 = 0010 0010
4、判断整数的奇偶。二进制末位跟1相与,如果最后一位为1为奇数,最后一位为0为偶数。10101110 & 1 = 10101110 此数为偶数,十进制为174。
按位异或
1、使某些特定的位翻转,要翻转的位跟1异或(相应的保留特定位的值就可以跟0异或)。如对数10101110的第2位和第3位翻转:10101110^00000110 = 10101000
2、实现两个值的交换,而不必使用临时变量。如交换两个整数a=10100001,b=00000110的值
a = a^b; //a=10100111
b = b^a; //b=10100001
a = a^b; //a=00000110
运算优先级
优先级 | 描述 | 优先级 |
---|---|---|
1 | 括号 | ()、[] |
2 | 正负号 | +、- |
3 | 自增自减、非 | ++、--、! |
4 | 乘除、取余 | *、/、% |
5 | 加减 | +、- |
6 | 移位运算 | <<、>>、>>> |
7 | 大小关系 | >、>=、<<= |
8 | 相等关系 | ==、!= |
9 | 按位与 | & |
10 | 按位异或 | ^ |
11 | 按位或 | | |
12 | 逻辑与 | && |
13 | 逻辑或 | || |
14 | 条件运算 | ?: |
15 | 赋值运算 | =、+=、-=、*=、/=、%= |
16 | 位赋值运算 | &=、|=、<<=、>>=、>>>= |
取值范围
类型 | 二进制范围 | 十进制范围 |
---|---|---|
int8 | 00000000~11111111 | -128 ~ 127 |
uint8 | 00000000~11111111 | 0 ~ 255 |
int16 | 0000000000000000~1111111111111111 | -32768 ~ 32767 |
uint16 | 0000000000000000~1111111111111111 | 0 ~ 65535 |
int32 | 0...0(32个)~1..1(32个) | –2,147,483,648 ~ 2,147,483,647 |
uint32 | 0...0(32个)~1..1(32个) | 0 ~ 4,294,967,295 |
int64 | 0...0(64个)~1..1(64个) | –9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 |
uint64 | 0...0(64个)~1..1(64个) | 0 ~ 18,446,744,073,709,551,615 |
发展史
计算机顾名思义是用来计算的机器。自古以来,人类就在不断地发明和改进计算工具,从古老的“结绳记事”,到算盘、计算尺、差分机,直到1946年第一台电子计算机诞生,计算工具经历了从简单到复杂、从低级到高级、从手动到自动的发展过程,而且还在不断发展。
1642年,法国数学家帕斯卡(Blaise Pascal)发明了帕斯卡加法器,这是人类历史上第一台机械式计算工具。
1673年,莱布尼茨研制了一台能进行四则运算的机械式计算器,称为莱布尼兹四则运算器。并且发明了二进制,被以后的计算机设计所采用,是计算机系统的关键。
1822年,巴贝奇开始研制差分机,专门用于航海和天文计算,在英国政府的支持下,差分机历时10年研制成功,这是最早采用寄存器来存储数据的计算工具,体现了早期程序设计思想的萌芽,使计算工具从手动机械跃入自动机械的新时代。
19世纪末,布尔发明了布尔代数,用于算术运算和逻辑运算。
1936年,图灵提出可计算理论,图灵机
香农利用布尔代数和二进制实现了所有的计算,并提出了信息论:要消除一个系统的不确定性,就必须使用信息。
1938年,德国工程师楚泽(Konrad Zuse)研制出Z-1计算机,这是第一台采用二进制的计算机。在接下来的四年中,朱斯先后研制出采用继电器的计算机Z-2、Z-3、Z-4。Z-3是世界上第一台真正的通用程序控制计算机,不仅全部采用继电器,同时采用了浮点记数法、二进制运算、带存储地址的指令形式等。这些设计思想虽然在朱斯之前已经提出过,但朱斯第一次将这些设计思想具体实现。
1945年6月,普林斯顿大学数学教授冯"诺依曼(Von Neumann)发表了EDVAC(Electronic Discrete Variable Computer,离散变量自动电子计算机)方案,确立了现代计算机的基本结构,提出计算机应具有五个基本组成成分:运算器、控制器、存储器、输入设备和输出设备,描述了这五大部分的功能和相互关系,并提出“采用二进制”和“存储程序”这两个重要的基本思想。迄今为止,大部分计算机仍基本上遵循冯"诺依曼结构。