前言
本人在经历一系列超时的折磨后,了解到了优化后幂运算:快速幂。
一、什么是幂运算?
一个数a,自乘x次的运算,a^x。
1.普通的幂运算代码实现
int pows(int a, int x)
{
int result = 1;
int i = 0;
for (i = 0; i < x; i++)
{
result *= a;
}
return result;
}
乍一看一个for循环了事,但是细一看好像有有点不对劲,如果指数或者底数为浮点数怎么办,如果指数小于1甚至为负数怎么办,都为0呢,问题倍出对不对。那么这段代码的运行效率怎么样,其实也不怎么样,一个for循环到底,时间复杂度为O(n)。
测试一下运行效率:用clock()函数计时。(记得添加time.h头文件)
#include<stdio.h>
#include<time.h>
clock_t start, stop; //clock_t为clock()函数返回的变量类型本质上是宏定义的一个长整型,相当于long
double time;
int main()
{
start=clock();
/*在这里就把需要测试的代码扔进去*/
stop=clock();
time=(double)(stop-start)/CLK_TCK;
printf("%lf\n",time);
return 0;
}
当然,运行结果是错的,指数爆炸(boom),数据大的离谱,大到long long都存不下,那结果为啥是0?因为底数取的是2,每乘一次2相当于左移一位,末位补零,超出long long存储范围自然就为0了。不过这不影响我们的测试结果:时间达到了惊人的180 秒。那么能不能进行优化呢?答案是肯定有的。
2.优化及测试对比
当然是减少指数的运算了,怎么减少呢?请看指数的运算法则:(直说了,这张图就是在网上扒的,嘿嘿。)
根据指数运算法则我们可以把2100000000 简化一步为450000000这样就少进行了五千万次的循环,测试一下。
x=x/2;/*指数除以2*/
n=n*n;/*底数进行平方*/
效果不错从180s减少到了89s。说明我们的方法是可行的。什么?你说如果指数是奇数怎么办?什么?你说我还想接着压榨指数怎么办?(万恶的资本家)来,上代码!(这里展示循环,当然也可以写成递归)
while (x > 0) {
if (x % 2 == 0) {
x = x / 2;
a = a * a;
} else {
x = x - 1;
result = result * a;
n = n / 2;
}
}
return result;
}
时间复杂度为O(log n)。
再次测试:
!!!0秒!!!是程序出错了吗?其实不是。
这是因为程序运行太快,colck()函数无法捕捉其运行时间。
解决方法有没有。当然有,是什么?
早在三千多年前我国就……(bushi)咳咳,说人话就是多次进行取平均,或者采取精度更高的计时。这里就简单来尝试第一种方法。
for(i=0;i<1000000;i++){
c=fastPow(a,n);
}
浅浅循环一百万次(真不多)
平均一下进行一次大约0.00006s 和前面的180s相比简直恐怖如斯!!!
当然,原本我以为已经结束的时候,看到了大佬的一篇文章。添加链接描述他甚至还使用了位运算接着优化,我本以为是取模运算,没想到是直接和1进行与运算来直接判断奇偶。具体可以自行尝试或者移步大佬文章。本人才疏学浅就不过多赘述了。
全部代码:
#include <stdio.h>
#include <time.h>
long long pows(int a, long long x);
int main(){
long long x;
int i,a;
clock_t start, end;
double t;
scanf("%d%lld",&a,&x);
long long c;
start = clock();//记录开始时间节点
c=fastPow(a,n);
end = clock();//记录结束时间节点
t = end - start;
printf("%lld\n",c);
printf("%lfs",t);
return 0;
}
long long fastPow(int a, int x){
long long result = 1;//注意此处为1而不为0
while (x > 0) {
if (x % 2 == 0) {
x = x / 2;
a = a * a;
} else {
x = x - 1;
result = result * a;//指数为奇数时别忘了将多余的1存起来
x = x / 2;
a = a * a;
}
}
return result;
}
总结:
以上就是我对快速幂算法的一点点见解。(新人第一次写博客,路过的大佬勿喷哈)当然也很感谢劝学的群友们,各位都很厉害,随口一句话就能令我受益良多,还是从他们口中了解到的快速幂。希望大家共同进步,我也要追上各位的脚步。