学习
实践
活动
工具
TVP
写文章
专栏首页神光的编程秘籍你觉得用不上的位运算里,隐藏着 CPU 实现的秘密

你觉得用不上的位运算里,隐藏着 CPU 实现的秘密

我们学 JS 的时候都会了解下位运算,在 React、Typescript 等源码中也频繁见到位运算的踪影,但在业务代码中从来不会这么写,它好像离我们很遥远。

但是位运算真的遥远么?

其实并不是。你写的所有代码最终都会转为位运算,位运算里隐藏着 CPU 实现的秘密。

下面我们就来谈一下位运算与 CPU 的关系以及位运算在代码中的应用。

从晶体管造 CPU

晶体管

先来了解下晶体管。

下面这个是三极管,它就是一种晶体管,特性是从一端通电,另外两端的电流就可以通过,不通电,另外两端的电流就不能通过。

这特性不就是一个开关么?

它和下面这个东西差不多,只不过不需要手动开关,而是通过通电来控制开关。

开和关,就是 1 和 0。计算机世界的组成单元 1 和 0 就是这么实现的。

逻辑电路

有了 01 就可以构成逻辑电路了,也就是与门、或门、非门、异或门等构成的电路。

它们的电路符号是这样的:

与门:

或门:

非门:

异或门:

它们在 JS 中怎么表示呢?

与 &

或 |

非 ~

异或 ^

它们就是通过三极管构成的逻辑电路的基本单元,能够实现基于 0 1 的逻辑。

什么逻辑呢?

1 & 0 为 0

1 | 0 为 1

~1 为 0

0 ^ 0 为 0

与或非大家比较熟悉了,这里讲一下异或:

异或是相同为 0,不相同为 1,也就是一个 0 和一个 1 才会得出 1,否则为 0

运算器

我们了解了位运算是什么,逻辑电路是什么,那有了逻辑电路能做什么呢?

能做的可多了,CPU 不就是一个大逻辑电路么,它就是建立在位运算基础上的。

比如我们实现下 ALU 运算器:

首先实现加法:

加法在二进制里面就是异或,不信我们来试一下:

1 和 0, 0 和 1 想加是 1 ,而 0 和 0,1 和 1 相加都为 0,这不就是异或么。

当然,还要处理进位,进位可以通过与运算得到,比如上面那四个,只有 1 和 1 相与才为 1,否则都为0,这就算出了进位。

能够按位相加和进位,就能实现加法器。

function add(a, b) {
    let sum = a;
    let carry = b;

    let temp;
    while(carry != 0) {
        temp = sum;
        sum = temp ^ carry;
        carry = (temp & carry) << 1;
    }

    return sum;
}

测试一下加法器:

注意,上面的与和异或不都有逻辑电路么,那用电路实现上面这段代码不就是硬件实现的加法器么?

有了加法,很容易就可以得到减法器:

function subtract(a, b) {
    var substrahend= add(~b, 1)
    var sub= add(a, substrahend)

    return sub
}

把被减数变为相反数,再和被减数相加不就是减法么?

至于这里为什么是取反加一,就涉及到原码反码补码了,

因为 1 对应 -1,而 0 呢?并没有 -0,所以就少了一位。所以要加一才能对上,也就是补码的“补”的意思,补上没有 -0 导致的缺少的那个编码。

实现了加法器、减法器之后,乘法和除法也就有了,因为乘法不就是多个加么?除法不就是多个减么?

就这样,我们从位运算实现了加减乘除。

对应到硬件上呢?就是我们通过三极管实现了逻辑电路,然后又用逻辑电路实现了加减乘除。

CPU

上面那个东西在 CPU 里叫做 ALU,算术逻辑单元,可以做逻辑运算、算术运算。

而且基于三极管还可以做到存储 0 1 等目的,构成寄存器。

有了这些东西我们就可以实现一个 CPU。

神不神奇,通过晶体管和位运算,我们就能把 CPU 造出来,虽然也就需要数亿个晶体管吧。

当然,我们只了解这些意义不大,还要了解位运算的应用。

位运算的应用

文件系统

看过我前面一篇文件系统实现原理文章的小伙伴会知道,硬盘会划分为数据块来使用,一个文件就是由多个数据块构成的:

文件会通过一个叫 inode 的结构来记录用到了哪几个数据块:

那我想存文件的时候,怎么知道哪些块可用呢?

一个块只有空闲和非空闲两种状态,一个位 0 和 1 就可以保存,所以会用位图这种结构来记录。

比如当我存储图片占用了 2 和 4 号块的时候,就会把位图的对应位置置为 1,否则为 0。那么当我需要存储文件的时候,从位图中查一下就知道哪些数据块可用了。

通过位图记录状态,通过位运算来判断状态。占用空间小,运算效率高。

操作系统级别都是这么干的,很多追求性能的库也都这么干。

React 和 Typescript

在 React 和 Typescript 等源码中,经常会见到一个叫 flags 的东西,flags 就和我上面说的位图差不多,通过一个位标识一个状态。

比如下面这段 React 的源码:

这就是判断了 这个 fiberNode 是否有 Placement 或者 Hydrating 的状态,如果有就 xxx。

再来看 Typescript 的源码中的这段代码:

~ 是取相反状态,再 & 就是判断是否没有这个状态,然后通过 | 设置到 flags 里面,意思就是这个 flags 加上没有 xx 状态的标识。

业务代码

操作系统、优秀的库中都用到了位运算,因为它们性能高,直接用电路算,存储空间也小,那是不是我们代码中可以用呢?

可以是可以,但是业务代码追求的更多是可维护性,如果你写出上面那种 typescript 的源码那样的位运算,后面接手的人不想打死你才怪。

总结

CPU 通过晶体管实现了电路的开关,也就是 0 和 1,然后组成了与或非异或门,进一步构成逻辑电路,逻辑电路可以实现加减乘除,构成 ALU,加上寄存器等部件就构成了 CPU。

所以位运算是直接用电路算,效率最高,其他的运算最终也会转为位运算。

操作系统文件系统的设计就用到了位图和位运算,React 和 Typescript 源码中也大量用到 flags。但这不意味着业务代码就可以用,因为业务代码还是可维护性更重要一些。

位运算里面隐藏着 CPU 实现的秘密,并不只是一个炫技的手段那么简单。

文章分享自微信公众号:
神光的编程秘籍

本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!

作者:神说要有光zxg
原始发表时间:2021-10-11
如有侵权,请联系 cloudcommunity@tencent.com 删除。
登录 后参与评论
0 条评论

相关文章

  • 专栏第 1 篇:从历史讲起,JavaScript 基因里写着函数式编程

    本瓜很喜欢看历史,读史可知兴替、使人明智,作为程序员看“技术的演替历史”同样如此。过程是越看越有味,仿佛先贤智慧的光照亮了我原本封闭的心,每每只能感叹一个“服”...

    掘金安东尼
  • 通过几行 JS 就可以读取电脑上的所有数据?

    好多同学看了这几篇文章后表示看的云里雾里的,其实这些策略里面都提到了一个漏洞:Spectre 漏洞,这个漏洞究竟有啥魔力,让浏览器频繁的为它更新策略呢,今天我就...

    ConardLi
  • 《源震》今日正式登录viveport,1元即可抢先体验

    VRPinea
  • 网站制作之WordPress的运行速度优化

    最近很多朋友吐槽wordpress速度慢,占cpu和内存,相比国内的PageAdmin、织梦这些主流的网站管理系统,wordpress在速度和负载上的确需要改进...

    用户4831957
  • 电脑技巧:Win10系统中的这六种模式介绍

    在Win10中,隐藏着很多不为人知的小秘密。有些小功能虽然看起来不起眼,但关键时候却能让我们的Win10跑得更爽,比如win10中六种不同的模式,该什么时候使用...

    IT技术分享社区
  • 解说: 图片隐写术

    隐写术是在显而易见的地方隐藏东西的主要例子。我们研究了在图像中隐藏信息的基本原理、一些方法和障碍。隐写术是有效地在显而易见的地方隐藏东西的主要例子。“隐写术...

    C4rpeDime
  • 你知道Thread线程是如何运作的吗?

    我们在Android开发过程中,几乎都离不开线程。但是你对线程的了解有多少呢?它完美运行的背后,究竟隐藏了多少不为人知的秘密呢?线程间互通暗语,传递信息究竟是如...

    陈宇明
  • 让 YAML 变得像它看起来一样简单

    如果你曾经尝试过写 YAML,你可能一开始会对它看起来很容易感到高兴。乍一看,经常用于配置文件、Ansible 剧本和普通文件数据库的 YAML 看起来就像购物...

    用户8639654
  • cpu参数_CPU核心参数有哪些

     要完成一个任务,先编写一段程序,然后存入计算机主存。程序的代码就会翻译成一条条指令或数据字。cpu就会执行这些指令得到最终结果。读取指令要通过地址读取,地址保...

    全栈程序员站长
  • 隐私计算平台效率问题和加速策略

    ?点击“博文视点Broadview”,获取更多书讯 目前,隐私计算平台广泛用到了多种安全技术,包括同态加密、秘密共享、差分隐私、可信执行环境,以及其他一些安全...

    博文视点Broadview
  • 20年未解的MIT密码难题,被自学成才的程序员破解了,比预计早15年

    它收到了一份富有仪式感的生日礼物,是个时间囊 (Time Capsule) :有人把重要的东西藏在里面,设定一个时间,留给未来的人类打开。

    量子位
  • BUU-Misc-第二章

    这里盲猜一波图片隐写,先丢到Stegsolve看看,进行数据通道提取分析 发现在Red plane 0 Green plane 0 Blue plane 0通道...

    Baige
  • 调皮的程序员:Linux之父雕刻在Linux内核中的故事

    因为LINUX操作系统的流行,Linus 已经成为地球人都知道的名人。虽然大家可能都听过钱钟书先生的名言:“假如你吃个鸡蛋觉得味道不错,又何必认识那个下蛋的母鸡...

    JackJiang
  • 现在都2202年了,用CPU做AI推理训练到底能不能行?

    机器之心原创 作者:思 CPU 不适合模型推理和训练?那已经是老刻板印象了,英特尔® 至强® 可扩展处理器搭配 AVX-512 指令集,单核一次能同时进行 12...

    机器之心
  • 汇编语言学习

       7、1Byte = 8bit ;    1KB = 1024B ;  1MB = 1024KB ;   1GB = 1024MB

    tandaxia
  • Go 语言内存管理(一):系统内存管理

    要搞明白 Go 语言的内存管理,就必须先理解操作系统以及机器硬件是如何管理内存的。因为 Go 语言的内部机制是建立在这个基础之上的,它的设计,本质上就是尽可能的...

    李海彬
  • 在《我的世界》里从零打造一台计算机有多难?复旦本科生大神花费了一年心血

    单枪匹马造出一个CPU乃至完整的电脑需要多长时间?有位大牛在《我的世界》游戏里用实际行动回答了这个问题:可能要花费一年多。

    量子位

扫码关注腾讯云开发者

领取腾讯云代金券