浅解快速幂

前言

本人在经历一系列超时的折磨后,了解到了优化后幂运算:快速幂。

一、什么是幂运算?

	一个数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;
}




总结:

以上就是我对快速幂算法的一点点见解。(新人第一次写博客,路过的大佬勿喷哈)当然也很感谢劝学的群友们,各位都很厉害,随口一句话就能令我受益良多,还是从他们口中了解到的快速幂。希望大家共同进步,我也要追上各位的脚步。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值