快速幂算法详解

news2024/11/14 23:33:47

目录

介绍

原理1

实现过程

原理2

取余运算

介绍

快速幂算法的目的就是让计算机很快地求出a^{b},暴力相乘的话,电脑要计算b次。用快速幂,计算次数在log_{2}b级别,很实用。

原理1

(1)如果将a自乘一次,就会变成a^{2}。再把a^{2}自乘一次就会变成a^{4}。然后是a^{8}…自乘n次的结果是a^{2n} 

(2)a^{x}\times a^{y}=a^{x+y}

(3)将b转化为二进制观看一下:比如b=\left ( 11 \right )_{10}就是\left ( 1011 \right )_{2}。从左到右,这些1分别代表十进制的8,2,1。可以说a^{11}=a^{8}\times a^{2}\times a^{1}

实现过程

假设我们拿到了a,并且b=11。想求a^{11},但是又不想乘11次,有点慢。

·以电脑视角稍稍观察一下b=11,二进制下是b=1011。

·制作一个base。现在base=a,表示的是a^{1}=a。待会base会变的。

·制作一个ans,初值为1,用来存放答案。

·循环一:看b(二进制)的最后一位是1吗? 是的。这代表a^{11}=a^{8}\times a^{2}\times a^{1}中的“\times a^{1}”存在。所以ans∗=base。

if(b & 1)
	ans *= base;

/*关于 b & 1:
x & y 是二进制 x 和 y 的每一位分别进行“与运算”的结果。
与运算,即两者都为 1 时才会返回 1,否则返回 0。
那么 b & 1

          二进制
b     =    1011
1     =    0001
b&1   =    0001

因为 1(二进制)的前面几位全部都是 0,
所以只有 b 二进制最后一位是 1 时,b & 1 才会返回 1。
挺巧妙的,并且很快。)*/

·然后base努力上升,它通过自乘一次,使自己变成a^{2}

base *= base;

同时

b>>=1

它把(二进制的)自己每一位都往右移动了。原来的最后第二位,变成了最后第一位b=\left ( 101 \right )_{2}

·循环二,再看看b,最后一位还是1。这说明有“\times a^{2}”,ans∗=base。

·base 继续努力,通过base∗=base 让自己变成了a^{4}。然后b也右移一位b=\left ( 10 \right )_{2}

·循环三,可是b的最后一位不再是1了,说明不存在“\times a^{4}”.base自我升华,达到了a^{8}。且b>>=1。这一步中,答案没有增加,可是毕竟b>0,还有希望。

·循环四,b的最后一位是1,这说明“\times a^{8}”的存在。ans∗=base。由于b再右移一位就是0了,循环结束。

总的来说,如果b在二进制上的某一位是1,我们就把答案乘上对应的a^{2n}。完整代码如下:

int quickPower(int a, int b)//是求a的b次方
{
	int ans = 1, base = a;//ans为答案,base为a^(2^n)
	while(b > 0)//b是一个变化的二进制数,如果还没有用完
    {
		if(b & 1)//&是位运算,b&1表示b在二进制下最后一位是不是1,如果是:
			ans *= base;//把ans乘上对应的a^(2^n)
		
        base *= base;//base自乘,由a^(2^n)变成a^(2^(n+1))
		b >>= 1;//位运算,b右移一位,如101变成10(把最右边的1移掉了),10010变成1001。现在b在二进制下最后一位是刚刚的倒数第二位。
	}
	return ans;
}

原理2

这是2017年NOIP普及组的完善程序第1题,这里提示的思路和上面不一样。

思路为:若当前p为偶数,只需把x自乘,然后p/=2 ,即考虑下一层,下几层会帮我们乘上\left ( x^{2} \right )^{p/2}

若当前p为奇数,说明x^{p}=x\times \left ( x^{2} \right )^{p/2}中前面那个x存在,ans∗=x。然后继续考虑下一层,下几层会帮我们乘上\left ( x^{2} \right )^{p/2}。注意,这里的x不是指题目开始给出的x,而是当前层的x应有的值,这跟上面的base是一样的。

比如假设我们拿到了x=3,并且p=11。想求3^{11}

·第一层循环b=11,一个奇数。将3^{11}分解为3^{1}\times \left ( 3^{2} \right )^{5}来看。本层只需把ans∗=3^{1}。后面的到下一层再搞定。下几层的总目标是让ans∗=\left ( 3^{2} \right )^{5},也就是让ans∗=9^{5}。来到下一层的方法是x=3∗3=9且b=11/2=5。

·第二层循环几乎独立于第一层存在。b=5,一个奇数。将9^{5}分解为9^{1}\times \left ( 9^{2} \right )^{2}来看。本层只需把ans∗=9^{1}。后面的到下一层再搞定。下几层的总目标是让ans∗=\left ( 9^{2} \right )^{2},也就是让ans∗=\left ( 81 \right )^{2}。于是x=9∗9=81且b=5/2=2。

·第三层循环b=2,不是奇数,只把81^{2}当作\left ( 81^{2} \right )^{1}。下几层的总目标是让ans∗=\left ( 81^{2} \right )^{1}。于是x=81∗81=6561,b=2/2=1。

·第四层循环,b=1,是奇数。这时候已经不用看成什么分解了,ans∗=6561就可完成总目标。b/2 为 0,结束循环。

代码和上面一样。因为b&1与b mod 2==1等效。b/=2与b>>=1等效。

取余运算

快速幂经常要结合取余运算。

取余运算有一些好用的性质,包括:

(A+B) mod b=(A mod b+B mod b) mod b

(A×B) mod b=((A mod b)×(B mod b)) mod b

于是快速幂过程中可以


	while(b > 0)
    {
		if(b & 1)
        {
			ans *= base;
            ans %= m;
    	}
		
        base *= base;
        base %= m;
		b >>= 1;
	}

 能保证这样下来最后的结果与“先乘到最后,再取余”的结果一样。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1414761.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VR拍摄+制作

1.VR制作需要的图片宽高是2:1,需要360✖️180的图片,拍摄设备主要有两种: 1)通过鱼眼相机拍摄,拍摄一组图片,然后通过PTGui来合成(拍摄复杂) 2)全景相机,一键拍摄直接就能合成需要的…

【智能家居】6、语音控制及网络控制代码实现

一、语音控制 1、指令结构体编写 这个结构体定义了一个命令输入的模型。在这个模型中,包含以下几个部分: cmdName:一个长度为128的字符串,用于存储命令名称。dvicesName:一个长度为128的字符串,用于存储设备名称。cmd:一个长度为32的字符串,用于存储具体的命令。Init:…

南卡Neo2评测:实力诠释骨传导耳机全能旗舰,细节展现匠心之作

前段时间朋友让我帮他寻找一款佩戴舒适、音质体验好的蓝牙耳机,因为比较忙所以一直把这件事搁置了,刚好这两天比较闲,所以也是在综合个人的经验和目前较为热门的一些品牌款式,决定帮他寻找一款骨传导耳机,因为骨传导耳…

手机视频压缩怎么压缩?一键瘦身~

现在手机已经成为我们日常生活中必不可少的工具,而在手机的应用领域中,文件的传输和存储是一个非常重要的问题。很多用户都会遇到这样一个问题,那就是在手机上存储的文件太多太大,导致手机存储空间不足,那么怎么在手机…

docker-compose Install influxdb1+influxdb2+telegraf

influxd2前言 influxd2 是 InfluxDB 2.x 版本的后台进程,是一个开源的时序数据库平台,用于存储、查询和可视化时间序列数据。它提供了一个强大的查询语言和 API,可以快速而轻松地处理大量的高性能时序数据。 telegraf 是一个开源的代理程序,它可以收集、处理和传输各种不…

[Python] 如何在Windows下安装图形可视化工具graphviz

什么是graphviz? Graphviz是一款开源的图形可视化工具,用于生成各种结构化数据的图形表示。它支持多种图形排列算法,可以将复杂的数据关系用图形的方式直观地展示出来。Graphviz广泛应用于软件工程、数据可视化、计算机网络以及其他领域的可视化分析中…

SpringBoot之时间数据前端显示格式化

背景 在实际我们通常需要在前端显示对数据操作的时间或者最近的更新时间,如果我们只是简单的使用 LocalDateTime.now()来传入数据不进行任何处理那么我们就会得到非常难看的数据 解决方式: 1). 方式一 在属性上加上注解,对日期进行格式…

【JavaEE进阶】 #{}和${}

文章目录 🍃前言🌳#{}和${}使⽤🚩Interger类型的参数(基础数据类型)🎈使用#{}🎈使用${} 🚩String类型的参数使用🎈#{}使用🎈${} 🎍#{}和${}区别&a…

中国新能源汽车持续跑出发展“加速度”,比亚迪迎来向上突破

2023年已经过去,对于汽车圈而言,2023年是中国车市的分水岭,在这一年,中国汽车工业70年以来首次进入全球序列,自主品牌强势霸榜,销量首次超过合资车。要知道,这是自大众于1984年进入中国市场成立…

【PLC 网络通信及 MODBUS TCP通信测试】

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、PLC的通信方式有?二、PLC网络通信1.MODBUS TCP 三、安装虚拟软件2.测试2.1 测试程序2.2 对接虚拟软件 总结 前言 提示:这里可以添加…

2024年人工智能产业十大发展趋势

2024年人工智能产业十大发展趋势 技术变革1. 多模态预训练大模型将是人工智能产业的标配2. 高质量数据愈发稀缺将倒逼数据智能飞跃3. 智能算力无处不在的计算新范式加速实现 应用创新4. 人工智能生成内容(AIGC)应用向全场景渗透5. 人工智能驱动科学研究&…

第8章 异常

第8章 异常 学习目标 能够辨别程序中异常和错误 说出异常的分类 说出虚拟机处理异常的方式 列出常见的5个运行时异常 列出常见的5个编译时异常 能够使用try…catch关键字处理异常 能够使用throw抛出异常对象 能够使用throws关键字处理异常 能够自定义异常类 能够处理自定义异常…

【精选推荐】3款强大的API渗透测试工具

1免责声明 请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,作者不为此承担任何责任。工具来自网络,安全性自测。 2前言 给大家介绍三款优秀的…

单片机学习笔记---独立按键控制LED显示二进制

这节我们来实现独立按键的第三个功能,独立按键控制LED显示二进制 新创建一个工程文件,然后上来我们就要把基本框架写好,这是基本的习惯 老规矩,然后把Delay 1ms的代码复制过来 复制过来后改造一下: 把1ms删掉&#x…

类和对象 第四部分:友元

在程序里,有些私有属性,也想让类外特殊的一些函数或者类进行访问,就需要用到友元的技术 友元的目的就是让一个函数或者类,访问另一个类私有成员 友元的关键字为friend 一.友元的三种实现 (一)全局函数友元 …

【Mybatis的一二级缓存】

缓存是什么? 缓存其实就是存储在内存中的临时数据,这里的数据量会比较小,一般来说,服务器的内存也是有限的,不可能将所有的数据都放到服务器的内存里面,所以, 只会把关键数据放到缓存中&#x…

解决:‘chromedriver’ executable needs to be in PATH

解决:chromedriver’ executable needs to be in PATH 文章目录 解决:chromedriver’ executable needs to be in PATH背景报错问题报错翻译报错位置代码报错原因解决方法方法一:检查python安装路径有没有添加到环境变量里面方法二&#xff1…

C# 命名管道NamedPipeServerStream使用

NamedPipeServerStream 是 .NET Framework 和 .NET Core 中提供的一个类,用于创建和操作命名管道的服务器端。命名管道是一种在同一台计算机上或不同计算机之间进行进程间通信的机制。 命名管道允许两个或多个进程通过共享的管道进行通信。其中一个进程充当服务器&…

JavaSE基础面试题-线程池原理

线程池原理 线程池做的主要工作是控制线程运行的数量,处理过程中将任务放入队列,然后在线程创建后,启动这些任务如果线程数量超过了最大数量,超出数量的线程排队等候,等其它线程执行完成,再从队列中取出执…

Nodejs前端学习Day1_补档

我给day1搞没了,还是觉得该补一个,有用 文章目录 前言一、学习目标二、学习目录三、为什么JavaScript代码可以在浏览器中运行四、为什么JavaScript可以操作DOM和BOM五、浏览器中的JavaScript运行环境总结 前言 补档 一、学习目标 二、学习目录 三、为什…