最近项目里涉及到了进制转换,顺带回忆一下二进制。。
背景
javascript
中很少会使用到二进制做处理, 但是最近开发时遇到了一个场景 :
admin
需要做一个对接 google ads
的工具, 以简化 marketing team
在做广告投放时做的一些重复性操作. 而其中涉及到一个流程: 将图片/zip/视频上传到 amazon aws s3
存储, 后端再上传到 google ads
. 其中有一种图片格式是 wbmp
, 这种格式浏览器并不支持, 所以需要转换, 其中就涉及到了 js 中的二进制转换。
计算机中以字节为单位存储和解释信息,规定一个字节由八个二进制位(比特)构成,即 1 个字节等于 8 个比特(1Byte=8bit)
二进制
先复习一下二进制, 数字在计算机中使用二进制表示, 有两个注意点:
- 有符号位: 最高位不表示数值, 表示符号
- 补码表示: 以原码形式表示数值
原码
以一个字节, 即 8 个二进制位为例, 第一位为符号位, 剩余为数字位
用原码, 可表示范围为: 11111111 ~ 00000000 ~ 01111111
按等比数列可得: - (2^7 - 1) ~ 0 ~ 2^7 - 1
即: -127 ~ 0 ~ 127
原码对人的识别友好, 但是在用原码计算时会出现问题:
1 | 00000001(1) + 10000001(-1) = 10000010(-2) |
这不是我们想要的
反码
反码是将数字位取反获得的, 其中规定:
- 正数反码, 为本身
- 负数反码, 数字位按位取反
即 11111111 的反码为 10000000
如果反码相加的话, 结果似乎是对的:
1 | -127: 原码: 11111111, 反码: 10000000 |
虽然结果是对的, 但是存在 -0 的情况, -0 和+0 是相等的, 没有意义
补码
还有一种表示形式, 补码
- 正数补码, 本身
- 负数补码, 反码的基础上 +1
网络上很多文章提到, 补码是为了解决反码相加得出正负 0 而提出的, 虽然能说得通, 但是
在既不能证实也不能证伪的情况下,只能存疑 — 周孝正
我们不讨论反码补码因为什么出现的, 只说明反码补码解决了什么问题
补码确实可以解决相加正负 0 的问题
1 | -127: 原码: 11111111, 反码: 10000000 补码: 10000001 |
怎么用 js 进行进制转换
- 表示形式
各进制数值在 js 中的表示时的前缀
- 2 进制:
0b
- 8 进制:
0
- 10 进制: 无前缀
- 16 进制:
0x
其中要注意的是符号位还是用 +-
表示, 如十进制 -12
表示为 2 进制是 -0b1100
,
表示为 8 进制是 -014
,
表示为 16 进制是 -0xc
,
- 转换方法
javascript
进制转换的方法主要有两个:
parseInt
: 其他进制转 10 进制
1 | // 按2进制解析 |
toString
: 将数字以任意进制表示
1 | // 假定有一个2进制数 |
精度问题
js 的所有数字,都是使用 64 位双精度浮点型来表示。并且是指数的形式。
转换成二进制后,就会有除不尽的问题:
1 | const a = 0.2; |
可以看到 0011 一直在重复,我们不能用有限的空间存储无限长度的数。
我们可以先转换成字符串,再按位数相加,大数相加也是一个道理。