拿起Bit的核武器来编程(基础篇)

世界上有10种人,一种人懂二进制,一种人不懂。

二进制

都知道程序的世界其实就是二进制的世界,一切的一切都是0和1。但是印象当中的二进制貌似都是黑客门用来耍酷的,我们普通程序员只能使用 高级语言 写写我们的CRUD。

黑客

二进制是他们的,我们(CRUD Boy)什么也没有。

我想告诉你们的是,二进制也可以是我们的。Please Follow Me。坐稳了,我要开车了。


1.从场景出发

1.1 问题

如下图,有一个快时尚品牌要做衣服的人工推荐,就给衣服做了个主题系列的分类。这样在衣服的详情页就可以直接推荐该衣服相关主题的其他的衣服了,而且可以直接从主题系列的菜单栏直接查看各种主题以及主题下的所有衣服。(如格子衬衫可以组合为为 一个"程序员主题",异装奇服可以组合为一个"万圣节主题")

但是这里有一个问题,就是主题内的商品如果没有库存,或者没有上架(等等,还有其他条件)是不能展示给用户的。这样才能更有效地推荐给用户,保证用户体验。

传统单体模式下,我想这个问题很容易解决,无非就是加一些过滤条件就好了。但是在微服务模式下,商品的状态不一定在商品中心维护。如商品的库存就会在库存中心维护,商品是否可以售卖可能在营销中心维护。

1.2 方案实现

微服务模式下,那只能再新建一个微服务,把这些转态聚合起来,并且提供查询服务给前台。

于是就有了下面这个简单的架构:


架构

相应地数据库就会像下面这样设计:


数据库-表设计

然后很自然地,提供给前端的查询服务就这么实现就可以了

SELECT 
    product_id
FROM
    theme_product
WHERE
    theme_id=1
AND inventory_state=1    --过滤库存
AND online_state=1       --过滤上下架状态
AND sale_state=1         --过滤是否可售卖
OFFSET 0 LIMIT 20

1.3 方案存在的问题

方案的问题

我们发现这个方案扩展性相对比较弱,且性能不高,如果后面再加入更多的状态,消耗的存储相对也比较高。

那有没有一种比较完美的方案呢?

1.4 比特登场

我们可以将所有商品的状态合并为一个字段:product_state,用每一个bit位来表示商品的每一种状态。如下所示


我们将所有的状态合并为一个tinyint类型的字段product_state,然后使用product_state的低3位分别来表示库存,上下架,是否可售卖的状态。这样商品的各种状态就可以直接转化为下面一个字段了。

对应的SQL查询语句也就变成 了下面这样

SELECT 
    product_id
FROM
    theme_product
WHERE
    theme_id=1
AND product_state=7  --商品状态
OFFSET 0 LIMIT 20

当我们这样去实现的时候,我们发现前面提到的3个问题都已经得到解决了。

  • 1.之前需要三个字段(且区分度太低)建联合索引,现在一个字段建索引,区分度高。
  • 2.只需要一个tinyint字段,就可以存储8种商品状态,扩展性高。
  • 3.基本上不需要修改schema。这里我们使用了tinyint类型可以存储8个字段,如果不是那么在意存储的话,可以直接修改为int类型,可以存储32个状态。当然这里使用tinyint字段是在业务迭代和存储之前做的一个权衡点。

2.回归Bit

通过上面的业务场景,我们发现其实我们CRUD boy竟然也能让Bit赋能我们的业务。


但是要想让Bit更好地为我们所用,我们就得看透它才行。所以下面我们就要回归Bit,看Bit本身到底有哪些骚操作。

2.1.程序世界中的数字【补码】

先记住结论:程序世界中的数字都是以补码的形式存在的

我们都知道,数字肯定是二进制表示的,那补码是个什么鬼?

在计算机中,为了区分正数和负数,人为规定最高位为符号位,其他位为真值位:

  • 符号位为0:正数
  • 符号位为1:负数
机器数

比如5(10) = 101(2),-5(10) = 100...00101(2)

那你是不是有一个疑问:那0呢?

记住结论:0在计算机中是正数。也就是说0的符号位为0。

那是不是说程序世界中的数字就是这样简单表示的呢?我们用Java来实验一下

System.out.println(Integer.toBinaryString(5));  // 101
System.out.println(Integer.toBinaryString(-5)); // 11111111111111111111111111111011

你会发现很神奇-5(10)=11111111111111111111111111111011(2)

这貌似跟我们的设想不太一样,按照之前的逻辑-5(2)应该是1000...0101。但是这两者之间貌似差得有点多。

2.2.原码,反码,补码

看到上面这个标题,是不是有点头疼。不慌,问题不大,请调整好坐姿,我们要发车了。


回顾一下之前的问题:为什么我们设想的-5的二进制表示和实际的二进制表示差别这么大
-5(10)= 11111111111111111111111111111011(2)
-5(10) =10000000000000000000000000000101(2)

结论:因为我们设想的-5的二进制表示是原码,而实际上计算机中的二进制表示用的是补码

那为啥需要补码呢?

在解释为什么之前,我们简单介绍一下这3中码之间的运算规则:


原码,反码,补码运算规则

如下是-5的原码,反码,补码的3种表示:


那你肯定要问:只要原码不就好了吗,为什么需要反码,补码呢?

结论:
反码:使用加法来代替减法
补码:解决了反码的问题后,还解决了+0和-0的二义性
所以,因为补码只需要加法器,而且还能区分+0和-0,所以计算机中的数字都是用补码表示的。

至于,为什么反码可以代替加法,补码可以解决+0和-0的二义性。请移步:

原码,补码和反码
原码、反码、补码的产生、应用以及优缺点有哪些

如果不想看这么复杂或者严谨的推到的话,我下面给一个例子来直接感受一下就好。

我们来计算十进制的表达式: 1-1=0

先看反码使用加法来代替减法
1.使用原码计算:1 - 1 = 1 + (-1) = [00000001] + [10000001] = [10000010] = -2【结果不正确】
2.使用反码计算:1 - 1 = 1 + (-1) = [0000 0001] + [1000 0001]= [0000 0001] + [1111 1110] = [1111 1111] = [1000 0000] = -0 【计算结果的真值部分正确

再看不满如何解决+0和-0的二义性
1-1 = 1 + (-1) = [0000 0001] + [1000 0001] = [0000 0001] + [1111 1111] = [0000 0000]=[0000 0000]

这样0用[0000 0000]表示, 而以前出现问题的-0则不存在了.而且可以用[1000 0000]表示-128:

-128 = (-1) + (-127) = [1000 0001] + [1111 1111] = [1111 1111] + [1000 0001] = [1000 0000]

2.3.奇怪的Math.abs方法

下面这段奇怪的代码来自于RocketMQ


有没有感觉很神奇,为什么取了绝对值之后还需要判断是不是负数呢?

没事,我们再看一个神奇的结果:


我们发现:Math.abs(Integer.MIN_VALUE)=Integer.MIN_VALUE

好了,请坐稳,我们又要开车了。
大多数人的解释是:因为int的取值范围为[-231,231-1],-a=231 ,向上溢出了,所以Math.abs(Integer.MIN_VALUE)=Integer.MIN_VALUE

这其实就是解释了个寂寞,向上溢出了为什么就这样呢?还是没有解释清楚其本质。

-a = ~a + 1,一个数的负数等于该数取反 ,然后+1

所以,我们来看一下运算过程:


运算后发现两者的二进制表示是一样的,所以Math.abs(Integer.MIN_VALUE)=Integer.MIN_VALUE

2.3.位运算

2.3.1 逻辑运算

位运算

注意:符号位也会参与逻辑运算

2.3.2 位移运算

直接看运算规则,不用记,只需要理解。


位移运算规则

下面我们来一个个理解运算的规则

  • 左移


    左移

左移后,低位就空出来了,因为是低位所以用0来填充

  • 右移


    右移

右移之后,高位空出,为了保证符号不变,高位空出来的部分与符号位一致

  • 无符号右移


    无符号右移

无符号右移是相对于右移而言的,差别主要高位填充的策略上。无符号右移统一高位填充0

\color{red}{请注意,位移运算没有无符号左移。至于为什么,请大家自己思考,并留言哦!!!}

至于为什么,请大家自己思考,并留言哦!!!

2.4.位移运算的数学意义

在数字没有溢出的前提下,位移操作是有数学含义的

位移运算的数学含义

简单看一下ArrayList的扩容,新容量 = 旧容量 * 1.5。这里就用了右移1位表示0.5倍


ArrayList扩容

好了,这次就聊到这里。这次主要聊一下基础性的东西。所谓基础不牢,地动山摇。下面一篇我们继续聊Bit的实际应用场景,相信会为你打开一扇Bit之窗,敬请期待!!!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,165评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,720评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,849评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,245评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,596评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,747评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,977评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,708评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,448评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,657评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,141评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,493评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,153评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,890评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,799评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,685评论 2 272

推荐阅读更多精彩内容

  • 进制 计算机在存储数字的时候都是以二进制的形式去存的十进制、十六进制、八进制、二进制 1.十进制 基数:0~9进位...
    我才是鳄鱼宝宝阅读 413评论 0 0
  • 一 各种进制 二进制:0,1两种八进制:标志的开头用0表示十六进制:标志的开头用0x表示 转换方式 除以进制 判断...
    guideEmotion阅读 406评论 0 0
  • 1、Java中的8种基本数据类型及其所占空间大小 数据类型字节数二进制位范围规律byte18-128~127-27...
    Albert_Yu阅读 548评论 0 1
  • 1.hashCode的作用 hashCode官方文档的定义 hashcode方法返回该对象的哈希码值。支持该方法是...
    croatoan阅读 1,246评论 0 0
  • 进制之间转换需要区分正整数和负数,平常的面试当中,还没有遇到相关的问题,笔试阶段可能碰到一两个,我在这里做一个简单...
    单调灬阅读 970评论 0 0