编码与进制
编码浅谈
引
有这样一句俗语: ”没有前面那个1,后面多少个0都无意义“
正
多项式
先从多项式讲起,一个数值可以表现出多项式的形式,如例1:
27017
=
2
×
1
0
4
+
7
×
1
0
3
+
0
×
1
0
2
+
1
×
1
0
1
+
7
×
1
0
0
27017 = 2 \times 10^4 + 7 \times 10^3 + 0 \times 10^2 + 1 \times 10 ^1 + 7 \times 10^0
27017=2×104+7×103+0×102+1×101+7×100
多项式的数学定义:
a
1
x
n
−
1
+
a
2
x
n
−
2
+
a
3
x
n
−
3
+
…
+
a
n
x
0
a_1\large x^{n-1} + a_2\large x^{n-2} + a_3\large x^{n-3} + \ldots + a_n\large x^{0}
a1xn−1+a2xn−2+a3xn−3+…+anx0
多项式在计算机程序中的表示:用一个变量表示多项式的基 var base = x \large _{}x x,用一个数组表示系数 var arr = [a1, a2, a3, … , an],数组的长度就是项数 n
任何一个数字都可以用不同 base 的多项式表示,所以一个多项式也可以转换为另一个不同 base 的多项式
对于例1,base = 10
则表现为[2, 7, 0, 1, 7]
Tips: 对于base = 10, arr = [0, 0, 3, 2, 5], 我们可以知道其值为325, 但如果是325, 是无法表现出[0, 0, 3, 2, 5], 也就是说,某些情况下,该运算不具有计算机程序中的可逆性
问题1:给定一个多项式,base已知,系数数组已知,如果要把它转换为另一个base2的多项式,base2 < base,那么base2需要一个多大的数组表示?
高base转低base,项数肯定会增多。首先,假设第一个多项式 base = b1 共 n 项,转换为第二个多项式 base = b2 共 m 项,现在就是要计算 m 的值。
一个多项式 X X X,base = b 1 b_1 b1 有 n n n项,则它的值保持在: b 1 n − 1 < = X < = b 1 n − 1 b_1^{n-1}<=X<=b_1^{n}-1 b1n−1<=X<=b1n−1
想要转化为 base = b 2 b_2 b2,假设有 m m m项,则它的值保持在: b 2 m − 1 < = X ′ < = b 2 m − 1 b_2^{m-1}<=X'<=b_2^{m}-1 b2m−1<=X′<=b2m−1,则可得出如下判断:
{ b 2 m − 1 < = b 1 n − 1 b 2 m > = b 1 n \begin{cases} b_2^{m-1}<=b_1^{n-1}\\ b_2^{m}>=b_1^{n}\\ \end{cases} {b2m−1<=b1n−1b2m>=b1n
化简得到:
{ m < = n l n b 1 l n b 2 ( m 向上取整 ) m > = ( n − 1 ) l n b 1 l n b 2 + 1 ( m 向下取整 ) \begin{cases} m<=n\frac{lnb_1}{lnb_2}(m向上取整)\\ m>=(n-1)\frac{lnb_1}{lnb_2}+1(m向下取整)\\ \end{cases} {m<=nlnb2lnb1(m向上取整)m>=(n−1)lnb2lnb1+1(m向下取整)
这里,我们需要考虑的是 m m m向上取整这个条件。因此,对于给定的多项式(base和n都已知),我们如果要得到base= b 2 b_2 b2对应的多项式表示,则 m m m的值为:
function m(b1, b2, n) {
return Math.ceil(n * Math.log(b1) / Math.log(b2))
}
问题2:给定一个多项式,base已知,系数数组已知,如何用程序转换为另一个已知base2(base2 < base)的多项式?
首先,假设第一个多项式 base = b1 共 n 项,转换为第二个多项式 base = b2 共 m 项,m已经在上一步计算出来了。
第一个多项式可以表示为
( ( ( ( a 1 b 1 + a 2 ) b 1 + a 3 ) b 1 + a 4 ) b 1 + … a n − 1 ) b 1 + a n ((((a_1b_1+a_2)b_1+a_3)b_1+a_4)b1+\ldots a_{n-1})b_1+a_n ((((a1b1+a2)b1+a3)b1+a4)b1+…an−1)b1+an
然后,将
a
1
a_1
a1转化为
b
2
b_2
b2多项式,类似与
a
1
=
c
1
×
b
2
t
−
1
+
c
2
×
b
2
t
−
2
+
…
+
c
n
×
b
2
0
a_1 = c_1 \times b_2^{t-1} + c_2 \times b_2^{t-2} + \ldots + c_n \times b_2^{0}
a1=c1×b2t−1+c2×b2t−2+…+cn×b20 得到数组arr
,每一项都小于
b
2
b_2
b2,该多项式的和为
a
1
a_1
a1
操作数组末位
c
n
c_n
cn
(
c
n
×
b
1
+
a
2
)
÷
b
2
(c_n \times b_1 + a_2) \div b_2
(cn×b1+a2)÷b2,结果作为新的
a
2
a_2
a2, 余数保留(unshift
)到新数组arr2
中,重复该行为,直到arr
的首位被处理,将余数和结果依次保留(unshift
)到新数组arr2
中。此时,得到了
a
1
b
1
+
a
2
a_1b_1+a_2
a1b1+a2的多项式数组
然后如此重复,直到计算完 a n a_n an项
程序如下:
const PolynomialTransformation = (base1, arr1, base2) => {
//先排除开头的0
let start = 0;
for(let i = 0; i < arr1.length; i++){
if(arr1[i] !== 0){
break;
}
else{
start++;
}
}
//全0返回空数组
if(start === arr1.length){
return [];
}
let arr2Length = Math.ceil((arr1.length - start) * (Math.log(base1) / Math.log(base2)));
let arr2 = new Array(arr2Length).fill(0);
let stepLength = arr2.length - 1;
for (let i = 0; i < arr1.length; i++) {
let carry = arr1[i];
let place = arr2.length - 1;
while (true) {
carry += base1 * arr2[place];
// 计算a1的b2多项式
// 取余
arr2[place] = carry % base2;
// 获取进位数
carry = Math.floor(carry / base2);
if (carry === 0 && place <= stepLength){
stepLength = place;
break;
}
place--;
}
}
return arr2;
};
这个函数可以做到多项式在不同进制间的转化
对于一个确定的多项式:
base = 62, arr 为 `(16) [31, 27, 52, 6, 3, 21, 0, 9, 13, 27, 2, 46, 26, 57, 59, 22]
base = 256 arr为 `(12) [78, 34, 113, 96, 17, 249, 156, 67, 183, 15, 179, 84]`
按上述的内容,对于base = 62, arr 的字符串映射为 'vrQ63l09dr2KqVXm'
,欲要转化为256,在此时就已确定了其长度:
Math.ceil(16 * Math.log(62) / Math.log(256)) // 12
假设期望的是14个长度,则无法做到
可以看出,如果base = 62, 则这个函数的逻辑就是Base62编解码的实现细节
如果我们定义自己的map:
// default map
const map = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
就可以得到自定义的base62了。这个和base62.js中的逻辑类似,它也有自定义字符集的操作
It’s also possible to define a custom character set instead ——原文内容
用
Base62编解码一般用在哪些地方?
Base62编码是由10个数字、26个大写英文字母和26个小写英文字母组成,多用于安全领域和短URL生成。
短网址编码流程:
- 将长地址与一个整数(int64)建立映射(一对多)
- 对上一步的整数进行Base62编码(10进制转62进制)
- 拼接上域名
B站的av,bv码为Base58编码
Base64编码
Base64编码是用64(2的6次方)个ASCII字符来表示256(2的8次方)个ASCII字符,也就是三位二进制数组经过编码后变为四位的ASCII字符显示,长度比原来增加1/3。
Base64 编码是对二进制数据进行编码,表示成文本格式,且只包含 A-Z、a-z、0-9、+、/、=这些字符
原理:把 3 字节的二进制数据按 6bit
一组,用 4 个 int 整数表示,然后查表,把 int 整数用索引对应到字符,得到编码后的字符串。
区别
表格如下:
项 | base62 | base64 |
---|---|---|
是否有进制转化 | 是 | 否 |
是否为流式处理 | 否 | 是 |
是否有header | 否 | 是 |
是否有事实标准 | 否 | 是 |