目录
源代码
long long ksm(long long a, long long k) // a代表底数,k代表指数
{
long long res = 1;
while (k)
{
if (k & 1)
res *= a;
k >>= 1;
a *= a;
}
return res;
}
解析代码(比如计算 3^19)
先将3^19如此转换
设最终结果:res=1,底数:a,指数:k(下表为二进制形式)(k==0时结束循环)
-
中间五个表达式都为相乘关系
-
空白:表示与上方的单元格内容一样
-
处理1:将X^2^0计算出来并乘上 res,若是 X^(0*2^0) 的格式,则直接跳过,因为值为1,乘不乘都可以(if (k&1) res *= a; )
-
处理2:将指数提一个2出来(k >>= 1)(此操作相对于 k /= 2)
-
处理3:将底数和指数中提出来的2进行计算,并使之称为新的底数( a *= a )
-
计算,将左方的五个数字相乘
步骤 | 备注 | res | a | k | |||||
---|---|---|---|---|---|---|---|---|---|
0 | 初始 | 1 | 3 | 10011 | |||||
1 | 处理1 | 3 | 3 | ||||||
处理2 | 01001 | ||||||||
处理3 | 9 | ||||||||
2 | 处理1 | 9 | 27 | ||||||
处理2 | 00100 | ||||||||
处理3 | 81 | ||||||||
3 | 处理1 | 1 | 跳过 | ||||||
处理2 | 00010 | ||||||||
处理3 | 6561 | ||||||||
4 | 处理1 | 1 | 跳过 | ||||||
处理2 | 00001 | ||||||||
处理3 | 43,046,721 | ||||||||
5 | 处理1 | 43,046,721 | 1,162,261,467 | ||||||
处理2 | --- | 00000 | |||||||
处理3 | --- |
所以最终结果是1,162,261,467
其中涉及到的知识点
按位与 &
先转换为二进制数,再对每一位进行与运算(一一得一,其余为零)
a | b | 二进制 a | 二进制 b | a & b (二进制) | a & b |
---|---|---|---|---|---|
5 | 5 | 101 | 101 | 101 | 5 |
5 | 4 | 101 | 100 | 100 | 4 |
5 | 3 | 101 | 011 | 001 | 1 |
5 | 2 | 101 | 010 | 000 | 0 |
5 | 1 | 101 | 001 | 001 | 1 |
5 | 0 | 101 | 000 | 000 | 0 |
还可以利用这个判断奇偶数,将一个数转换为二进制的如下形式
从到2n(n>1)都是偶数,偶数加偶数还是偶数,
是奇数,所以看一个数的奇偶数,就看0位了
也就是 N & 1 == 1 的话,则说明是奇数
移位运算 [ 右移(>>)为例 ]
转换成二进制后,将整体往右移一定位数,即,右移2位就是去掉最右边两位,左移反之
a | b | 二进制 a | a >> b(二进制) | a >> b |
---|---|---|---|---|
5 | 3 | 101 | 000 | 0 |
5 | 2 | 101 | 001 | 1 |
5 | 1 | 101 | 010 | 2 |
还有就是左/右移有个小细节:
一个无符号的int类型的数3的二进制形式:00000011(若该类型为八位的话)
左/右移的话(也就是相当于去到最右/左边的一位数):
左移后:0000011?
右移后:?0000001
其中,问号原先是不在该数据的界限之内,所以是不清楚他原先是0还是1
(我记得其中一个以为运算是补上0的,但我忘记了,而我也懒得去尝试了)