近日看到一道算法题:
这个题目引起了我的兴趣,
于是我着手开始设计算法,以下便是我想到并琢磨改良出的第一个解法:
//used用来累计使用乘法的次数
#include <stdio.h>
#include <stdlib.h>
#define NUMBER 2
#define P 62
int used = 0;
//62=32+16+8+4+2
long long p(long long x, int in) {
long long number = 1;
do {
if (in & 1) {
number *= x;
++used;
}
} while ((in >>= 1) && ((x *= x), (++used), 1));
//这里while内的乘法也被计入
return number;
}
int main() {
printf("%d的%d次方的值:%lld\n", NUMBER, P, p(NUMBER, P));
printf("计算%d的%d次方的乘法使用次数:%d\n", NUMBER, P, used);
}
算法很简短,计算速度很快,也不占用空间,主要依靠幂的最右边的二进制位是否为1来判断是否相乘从而使幂相加(同底数幂相乘,底数不变,指数相加),使得幂最终达到62,算出N^62次方的值。
Tip:(x *= x)之所以不写在循环体内,是因为这样可以减少掉最后使那一次无意义的乘法
通过计算器可知结果是对的,可是步骤仍然太多,需要足足10步…
于是我开始寻思更好的改良方法,但可惜我觉得这个算法已经是最优了
所以我开始搜索,看看网上有没有关于这个问题的解法
于是我看到这个时(https://bbs.csdn.net/topics/190051933)
我有了一丝灵感。
迅速的,我经过一些试错和思考,决定特化算法,写出一个针对X^62次方的算法
最终成果如下:
//used用来累计使用乘法的次数
#include <stdio.h>
#include <stdlib.h>
#define NUMBER 2
#define P 62
int used = 0;
//62=32+16+8+4+2
long long p(long long x, int in) {
long long number = x;
int in_save = in;//保存in值
int num = 1;//上限值的幂
do{
number *= number;
++used;
num <<= 1;
}while ((in >>= 1));
//此时number是上限值,在这里number是2^64次方
//该值太大,使得在这里时,number成了0,但因为算法不依靠number的值,所以无影响
num -= in_save;
//64-62得出2,这意味着我需要把number除以2^2就能得出2^62的值
do {
if (num & 1) {
number /= x;
//除以x可看做是乘以x的倒数,所以这里除法,我看做为乘法
++used;
}
} while ((num >>= 1) && ((x *= x), (++used), 1));
//这里while内的乘法也被计入
return number;
}
int main() {
printf("%d的%d次方的值:%lld\n", NUMBER, P, p(NUMBER, P));
printf("计算%d的%d次方的乘法使用次数:%d\n", NUMBER, P, used);
}
8步!我解掉了!
运行图:
恩?你问这个2^62的计算结果不对?这其实只是计算出的值过大导致的数值错误,但我这里的算法是以幂为依据做循环和计算的,所以结果不影响。
如果你还不相信,我们可以看看2^31次方结果如何,来看看这个算法是否正确!
可以看出,我的算法没有问题,这就是能正确以8步来计算X^62次方的算法!且无论X初始是多少。
好,此题已解,谢谢观看,如有错误,欢迎指出。