学习Protobuf,ZigZag是啥你真的知道么?

简介:

结合上一篇文章《学习Protobuf,Varint是啥你真的知道么?》,我们了解到通过Varint 编码整数,如遇到负数或大整数,就不具备压缩优势了?由于引入了MSB,不但没有好的压缩效果,还加大了存储,这明显不是我们想要的。以下,我们聊聊怎么解决这类问题。

这篇文章,也是学习Protobuf过程中偶然所得,算法简洁,篇幅较短,预计阅读时间 8 分钟,如果对您有帮助,还望不吝评价,求点赞、求评论、求转发

在聊ZigZag算法之前,我们先聊聊进制原码反码补码相关的知识点,如果你懂,可跳过直接往下翻。

什么是进制?

所谓进制,就是当某一位上的信息满时,需要往前进位。比如,十进制,就是当某一位上的数满十时进位;而某一位上的数满二时进位就是二进制,等等。

进位之间都可以相互转化,例如: 十进制:10 → 二进制:1010 → 十六进制:A

我之前看过一个答案,说:为什么十进制比较通用? 因为咱人类只有 10 个手指头,数一遍刚好十个数,所以十进制自然就成为默认的进制。那如果人类长 11 手指头,说不定就是十一进制。

后来计算机的出现,一个数据的有无是最天然的信息承载单元,所以由 0 和 1 组成的二进制很自然成为计算机的进制方式。—— 老苗

计算机系统里面对二进制定义了原码反码补码,为了更简单的理解,后续我们用1 Byte=8 bits进行讲解。

原码是啥?

定义: 用第一位表示符号(0为非负,1为负数),其余位表示值,如下:

  • +8 -> 原码:0000 1000
  • -8 -> 原码:1000 1000

有了原码的表示方法就可以对数进行算法运算,但是很快就发现用带符号位的原码进行乘除运算结果正确,但在加减运算时就出现了问题,如下:

乘法规则:符号位做“异或”运算,数值位做类似十进制的“乘法”运算
十进制:+8 * (-8) = -64
原码:0000 1000 * 1000 1000 = 1100 0000 = -64

十进制:+8 + (-8) = 0
原码:0000 1000 + 1000 1000 = 1001 0000 = -16  # 显然不正确

看起来加法运算也没什么问题,发现问题是出在符号位上?于是计算机大佬们引入了反码

反码都做了啥?

定义: 用第一位表示符号(0为非负,1为负数),其余位,非负数保持不变,负数按位求反,如下:

  • +8 -> 原码:0000 1000 -> 反码:0000 1000
  • -8 -> 原码:1000 1000 -> 反码:1111 0111

我们继续进行上述的加法运算

  • 十进制:+8 + (-8) = 0
  • 反码:0000 1000 + 1111 0111 = 1111 1111 = -0

竟然结果是-0,这个结果让人猝不及防啊!!!

分析发现,如果用原码 + 补码表示二进制计算,表面上看,似乎挺好的。不过仔细思考就会发现两个问题:

第一,0竟然可以用两种编码表示,+0 和 -0:

  • +0 -> 原码:0000 0000 -> 反码:0000 0000
  • -0 -> 原码:1000 0000 -> 反码:1111 1111

第二,计算机不清楚符号位的存在,因此参加运算后,会出现结果为-0这样的现象。

这看起来怪怪的,为了解决这些问题,计算机巨佬们又引入了补码

补码有啥用?

定义: 用第一位表示符号(0为非负,1为负数),剩下的位非负数保持不变,负数按位求反且末尾加一。

  • +8 -> 原码:0000 1000 -> 补码:0000 1000
  • -8 -> 原码:1000 1000 -> 补码:1111 1000

现在我们继续看看,把符号位带入运算会出现什么结果?

-> 8 + (-8)
-> 0000 1000 + 1111 1000
-> 0000 0000
-> 0

很明显,通过引入补码,我们解决了此类问题,计算机运算过程中,就不用关心符号问题,统一按照满二进一规则处理即可

好了,知识小点就说到这了,接下来,进入真正的主题。

ZigZag 是什么?

在大多数计算机系统中,我们通常使用定长整型(fixed length intergers)表示数值。比如:

  • 4 bytes表示Int32
  • 8 bytes表示Int64

为什么这样设置呢?这样能便于我们的计算机处理,加快处理的速度。

但是在系统网络通信(RPC)时,为了传输一个1,我们需要传输00000000 00000000 00000000 00000001 32 个 bits。这么多字符,而有价值的数据只有 1 位,这T&M也太浪费了呀!

那该怎么办呢?ZigZag算法由此而生。

ZigZag 的原理

编码介绍

ZigZag编码将有符号整数映射成无符号整数,以便绝对值较小的数字对应较小的编码值,比如:-1 -> 11 -> 2,具体如图:

原数 编码
0 0
-1 1
1 2
-2 3
2 4
... ...
-(2^31 -1) 2^32 - 3
2^31 -1 2^32 -2

如上,这种方式通常由正整数和负整数来回曲折编码,看着还挺有意思的。难道就因为这样,计算机大佬们才给取了个名字叫ZigZag(锯齿形线条)算法???

编码规则

  • a.非负整数,符号位后移
  • b.负整数,符号位后移,数据位按位求反

在大多数计算机系统中,以4 Bytes 8 Bytes 来表示整数(Int32、Int64)。下面我们选择Int32进行一个简单的演示,如下:

  • 十进制:0\
-   补 码 : **0**0000000 00000000 00000000 00000000\

-   ZigZag:00000000 00000000 00000000 0000000**0**
  • 十进制:1\
-   补 码 : **0**0000000 00000000 00000000 00000001\

-   ZigZag:00000000 00000000 00000000 0000001**0**
  • 十进制:-1\
-   补 码 : **1**1111111 11111111 11111111 11111111\

-   ZigZag:00000000 00000000 00000000 0000000**1**

解码规则

  • 类似编码,反向操作即可

ZigZag 编码实现(Python)

def int32_to_zigzag(n):
    return (n << 1) ^ (n >> 31)

ZigZag 解码实现(Python)

def zigzag_to_int32(zz):
    return (zz >> 1) ^ -(zz & 1)

总结一下

大多数情况下,通过ZigZag编码结合Varint算法,对整数都有好的压缩效果,但如果遇到绝对值大的整数,就不再具有压缩优势了。

不过,我们通常使用到的整数往往也都比较小。

参考文档

❤️❤️❤️读者每一份热爱都是笔者前进的动力! 我是三十一,感谢各位朋友:求点赞、求评论、求转发,大家下期见!

相关文章
|
前端开发 Java 测试技术
基于SSM的大学生电信诈骗宣传系统设计与实现
基于SSM的大学生电信诈骗宣传系统设计与实现
620 0
|
前端开发 Android开发 容器
surfaceview组件的surfaceCreated()不被调用的解决方案
原文:surfaceview组件的surfaceCreated()不被调用的解决方案 有时候我们有需要在native层做在surfaceview的上下文中做渲染,这个时候只是提供了一个单独什么都不做的surfaceview。
4049 0
|
3月前
|
小程序 PHP 图形学
热门小游戏源码(Python+PHP)下载-微信小程序游戏源码Unity发实战指南​
本文详解如何结合Python、PHP与Unity开发并部署小游戏至微信小程序。涵盖技术选型、Pygame实战、PHP后端对接、Unity转换适配及性能优化,提供从原型到发布的完整指南,助力开发者快速上手并发布游戏。
|
缓存 自然语言处理 JavaScript
万字长文深度解析JDK序列化原理及Fury高度兼容的极致性能实现
Fury是一个基于JIT动态编译的高性能多语言原生序列化框架,支持Java/Python/Golang/C++/JavaScript等语言,提供全自动的对象多语言/跨语言序列化能力,以及相比于别的框架最高20~200倍的性能。
169125 12
|
消息中间件 关系型数据库 数据库
Python实时监测数据库表数据变化的方法
在实现时,需要考虑到应用的实时性需求、数据库性能影响以及网络延迟等因素,选择最适合的方法。每种方法都有其适用场景和限制,理解这些方法的原理和应用,将帮助开发者在实际项目中做出最合适的技术选择。
785 17
|
11月前
|
人工智能 监控 测试技术
阿里云磐久服务器稳定性实践之路
阿里云服务器质量智能管理体系聚焦自研服务器硬件层面的极致优化,应对高并发交付、短稳定性周期、早问题发现和快修复四大挑战。通过“三个重构”(质量标准、开发流程、交付模式)、“六个归一”(架构、硬件、软件、测试、部件、制造)策略,实现芯片、整机和云同步发布,确保快速稳定上量。此外,全场景测试体系与智能预警、分析、修复系统协同工作,保障服务器在萌芽阶段发现问题并及时解决,提升整体质量水平。未来,阿里云将继续深化大数据驱动的质量管理,推动服务器行业硬件质量的持续进步。
|
存储 监控 算法
动物目标检测——基于YOLOv5和树莓派4B平台
【10月更文挑战第1天】本文将详细介绍如何在性能更强的计算机上训练YOLOv5模型,并将训练好的模型部署到树莓派4B上,通过树莓派的摄像头进行实时动物目标检测。
433 2
|
存储 分布式计算 算法
基于 Log 的通用增量 Checkpoint
本文将从 Checkpoint 的性能优化历程出发,介绍 ChangelogStateBackend 的基本机制、应用场景和未来规划,同时介绍最新版本在 State 上的一些优化工作。
7761 2
基于 Log 的通用增量 Checkpoint
|
算法 图形学 C++
复杂多边形的三角剖分
复杂多边形的三角剖分
394 0
|
机器学习/深度学习 编解码 自然语言处理
【VIT】小白入门篇:从各个角度认识Vision Transformer
【VIT】小白入门篇:从各个角度认识Vision Transformer
1289 0
【VIT】小白入门篇:从各个角度认识Vision Transformer