谁说CURD不会用到二进制?

347 阅读3分钟

突然想起来一个有趣的事情,离开学校以后,很多人顺其自然就接受了一些 “现实” ,就好像大家有着相同的默契:给一些很少使用或非常基础的东西打上不会用的标签。就如同二进制,很多人第一想法就是我每天写的都是业务代码,怎么会用到二进制?所以,今天和大家聊一聊 二进制位运算 在业务场景中的应用

目录

  • 常用的位操作有哪些
  • 举个栗子

常用的位操作有哪些

一、按位与

将二进制的每一位进行 操作,如果两个值都为 1 则操作位的值为 1

$a = 7;
$b = 4;

// 将 $a $b 进行按位与操作时
// 会将这两个数隐式转换为二进制进行比较
// 111 & 100
// 将 111 与 000 的每一位进行互相比较
// 得出 100 也就是十进制数 4
$a & $b === 4;

二、按位或

将二进制的每一位进行 操作,如果两个值中有一个为 1 则操作位的值为 1

$a = 7;
$b = 4;
// 111 | 100
// 得出 111 也就是十进制数 7
$a | $b === 7;

三、异或

将每一位进行比较,如果两个值相等,则操作位的值为 0 否则为 1

$a = 7;
$b = 4;
// 111 ^ 100
// 得出 011 也就是十进制数 3
$a ^ $b === 3;

四、移位

移位运算分为左移、右移 左移运算符将二进制整体向左移动,空出的位置补 0

$a = 2 << 3;
// 将 10 向左移动 3 位,空出的位置补 0
// 得出 10000 也就是十进制数 16
// 这里可以看出其实 a << b 可以看成 a乘以2的b次方
$a === 16;

右移运算符将二进制整体向右移动,溢出的位将舍弃

$a = 10 >> 3;
// 将 1010 向右移动 3 位,溢出的位舍弃
// 得出 1 也就是十进制数 1
// 大家可以想一想 a >> b 右移运算可以看成什么公式呢
$a === 1;

举个栗子

组件参数简化

当有一个组件依赖很多由客户端来决定是否使用的选项时,可以通过二进制位操作来简化,从而开放出更简单、灵活的API。 常用的 json preg 系列函数都采用了此方式来设计

json_encode($a,JSON_UNESCAPED_UNICODE^JSON_UNESCAPED_SLASHES);

实现思路主要是用二进制的每一位来表示一个选项,只需要判断对应位是否为 1 就能知道是否选择此选项 伪代码如下:

// 附加朋友数据
const WITH_FRIENDS = 1;
// 附加学校数据
const WITH_SCHOOL = 2;
// 附加公司数据
const WITH_COMPANY = 4;

// 查询用户,并根据选项判断附加数据
function getUser($options) {
    if ($options & WITH_FRIENDS) {
        $user->friends = $friends;
    }

    if ($options & WITH_SCHOOL) {
        $user->school = $school;
    }

    if ($options & WITH_COMPANY) {
        $user->company = $company;
    }

    return $user;
}
// 查询用户,并附带返回朋友以及公司信息
// 多个选项使用 `按位或` 操作来得出一个最终值
getUser(WITH_FRIENDS | WITH_SCHOOL);

判断一个十进制数字的二进制第n位的值是否为0

这是之前偶然看见的一道面试题,这里可以使用 按位与 左移 操作来完成。伪代码:

$number = 2454;
$n = 4;
// 其实只需要将 $number 和 一个 第 $n 位为 1 其他位为0的数进行 & 运算即可
// 结果为 0 则第 $n 位为 0 反之为 1
$isZero = ($number & (1 << ($n -1))) === 0;
// $number 二进制为 100110010110 第四位为 0
// $isZero === true

最后

上面简单举了两个小栗子,其实很多其他的场景可以使用二进制位运算来实现,比如简单权限系统,高级使用场景还有 bitMapBloomFilter 等,也欢迎朋友们一起来讨论讨论还有哪些其他平常容易被忽略却非常实用的基础知识呢?

本文首发于我的博客,欢迎来我的博客玩耍,也欢迎友链~

本文使用 mdnice 排版