最近在读《计算机科学导论》,想要对于编程了解更多,就免不了去了解计算机的底层知识。记录下阅读所感或总结,暂时不懂的也没关系,过段时间再读一遍或许有不一样的收获。
该操作分为两个步骤,对整数部分与小数部分分开进行转换。先给出两个步骤的流程图。
以十进制数 6.25 为例转换为二进制数。
首先处理整数部分:
- 6 / 2 得 3 余 0
- 3 / 2 得 1 余 1
- 1 / 2 得 0 余 1
所以得到转换后的二进制整数部分为 110
接下来处理小数部分:
- 0.25 * 2 得 0.5 取整数部分 0
- 0.5 * 2 得 1 取整数部分 1
所以得到转换后的二进制小数部分为 01
最终结果为 110.01,那么尝试着用代码来实现一下这个过程。
function decimalToBinary(num, target/* 目标进制 */) {
// 分离整数和小数
let [int, deci] = String(num).split('.');
const result = [];
// 先处理整数
int = parseInt(int, 10);
if (int === 0) result.push(0);
while (int !== 0) {
result.unshift(int % target);
int = parseInt(int / target, 10);
}
// 处理小数
if (deci) {
deci = parseFloat(`0.${deci}`);
result.push('.');
while (!Number.isInteger(deci)) {
deci *= target;
result.push(parseInt(deci, 10));
}
}
return result.join('');
}
console.log(decimalToBinary(6.25, 2));
相比起十进制转换为二进制,二进制转十进制更简单一些。
以二进制数 1010.101 为例进行转换。(**表示幂运算)
- 整数部分为:
2**0 * 0 + 2**1 * 1 + 2**2 * 0 + 2**3 * 1 = 10
- 小数部分为:
2**-1 * 1 + 2**-2 * 0 + 2**-3 * 1 = 0.625
最终结果为 10.625,以下为代码实现。
function binaryToDecimal(num) {
let [int, deci] = String(num).split('.');
int = int.split('').reverse().reduce((ret, item, index) => ret + item * 2 ** index, 0);
if (!deci) return int;
deci = deci.split('').reduce((ret, item, index) => ret + item * 2 ** (-index - 1), 0);
return int + deci;
}
console.log(binaryToDecimal(1010.101));
八进制、十六进制转换为十进制,与二进制转换为十进制类似,唯一的不同就是底数。
- 无符号表示法
- 符号加绝对值表示法
- 二进制补码表示法
目前几乎所有的计算机都采用二进制补码表示法来存储数字。
要了解二进制补码表示法需要先了解反码和补码的运算。
-
反码:简单反转各个位,将0变为1,1变为0。例:10010 => 01101
-
补码:补码有两种计算方法。例 10010 => 01110
- 先进行一次反码计算,然后加1
- 从最右侧开始复制位,直到有1被复制,接着对其余的位取反码
二进制补码表示法在存储数字的时候,有效范围为0 ~ 2**n -1
,并且该范围会被划分为两个相等的子范围,左半边存储正整数,右半边存储负整数。最后,这两半会按照左负右正的习惯进行位置交换。书中图例如下:
然后来看二进制补码表示法具体是如何存储整数的。
-
存储
- 将整数转换为二进制数
- 如果整数是正的或者是零,直接存储。如果是负数,对其进行补码操作,然后存储
-
取出
- 如果最左位是1(负数),计算机对其进行补码操作,如果最左位是0(正数),不进行任何操作
- 将二进制数转换为十进制数(加上正负号)
二进制运算在平时使用js的时候很少有机会使用,所以之前也没有仔细看过。现在仅记录运算的规则,等到有机会进行实践的时候再来重新温习这一章。
- 非(NOT),一元运算符。对输入进行反转。0变为1,1变为0。
- 与(AND),二元运算符。接受2个输入,如果都是1,则输出1,否则输出0。
- 或(OR),二元运算符。接受2个输入,如果都是0,则输出0,否则输出1。
- 异或(XOR),二元运算符。接受2个输入,如果输入相同则输入0,否则输出1。
- 右移,把每一位向右移动一个位置,最右位丢失,最左位填0。
- 左移,与右移操作相反。
计算机的组成主要分为三大类。
用于数据的运算。主要包含三个组成部分:算术逻辑单元、控制单元、寄存器组。
存储单元的集合,每个存储单元都有唯一标识,就是所谓的“地址”。
存储器分为RAM
和ROM
。
由于计算机需要很多存储器,但由于高速存储器价格高昂,所以会采用存储器分层。对于速度要求较高时会采用高速存储器,中速存储器用来存储经常访问的数据,而低速存储器则存储访问频率较低的数据。
主要包含键盘、鼠标、外接硬盘等设备,使计算机具备与外界通信的能力。
协议分层的必要性不言而喻,每一层使用更低层的服务,同时向更高层提供服务。如果需要替换某一层的服务,则只需对该层进行修改或替换,而不影响高层和低层。
作为TCP/IP
协议簇中的最高层,该层不向其他协议提供服务,仅仅是接收传输层对其提供的协议进行消费。常见的有FTP
、Telnet
、SMTP
、HTTP
、RIP
、NFS
、DNS
等。
传输层的第一个义务是提供进程间的服务,有多种办法来完成进程间的通信,最常用的是通过端口(PORT),端口号是0 ~ (2**16 - 1)
之间的整数表示的。该层常见的协议主要是UDP
、TCP
。
主要负责源到目的地的消息发送。
该层是网络中连接起来以后能够构成因特网的区域。能够通过有线或无线的形式来完成。
将数据链路层接收的位转换成用于传输的电磁信号。