计算指数
计算大指数背景:这是一篇有关如何快速有效地计算大数指数的快速文章。
从基本的乘法算法开始,它随后给出了更快的算法和一些快速示例。
本文中使用的技术可用于一般数学,加密等。
在本文中,使用以下约定:
^运算符是指指数,而不是按位异或运算。 所以2 ^ 3是2立方= 2 * 2 * 2
*是乘法
%是mod是模块化除法。 例如10 mod 3≡1。
log2代表日志库2。
我们如何计算指数? n ^ exp
****************************************************** *******
方法1:简单方法我们学习计算指数的第一种方法是扩展和乘除方案。 让我们以7 ^ 13为例:
7 ^ 13 = 7 * 7 * 7 * 7 * 7 * 7 * 7 * 7 * 7 * 7 * 7 * 7 * 7
7 * 7 = 49
49 * 7 = 343
343 * 7 = 2401
2401 * 7 = 16807
16807 * 7 = 117649
117649 * 7 = 823543
823543 * 7 = 5764801
5764801 * 7 = 40353607
40353607 * 7 = 282475249
282475249 * 7 = 1977326743
1977326743 * 7 = 13841287201
13841287201 * 7 = 96889010407
代码明智:请注意,为简洁起见,我们将为本文中的所有代码设置以下框架:
我们创建一个幂函数:
长战俘(长n,长exp);调用函数的示例:
System.out.println(“ 7到13的幂=” + pow(7,13));其中exp> = 1
long pow(long n, long exp){
long power, prod;
prod = n; // hold the product of our multiplication.
for (power = 2; power <= exp; power ++)
{
prod *= n; // prod = n^power
}
return prod;
}
尽管这适用于较小的指数,但对于较大的指数,则需要大量工作。
当然,必须有更好的方法。
乘法数:
exp-1
****************************************************** *******
方法2:分而治之指数性质:
如果c = a + b
n ^ a * n ^ b = n ^ c
以我们的示例为例,我们可以有:
13 = 6 + 7
所以7 ^ 13 = 7 ^ 6 * 7 ^ 7!
7 * 7 = 49 = 7 ^ 2
49 * 7 = 343 = 7 ^ 3
343 * 7 = 2401 = 7 ^ 4
2401 * 7 = 16807 = 7 ^ 5
16807 * 7 = 117649 = 7 ^ 6
117649 * 7 = 823543 = 7 ^ 7
117649 * 823543 = 96889010407 = 7 ^ 6 * 7 ^ 7 = 7 ^ 13
在代码方面,这可能类似于:
long pow(long n, long exp){
long halfexp = exp / 2;
long power, prod, prod2;
prod = n; // hold the product of our multiplication.
for (power = 2; power <= halfexp; power ++)
{
prod *= n; //prod = n^power
}
if (exp % 2 == 0)
prod2 = prod;
else
prod2 = prod *n;
return prod * prod2;
}
prod最终等于7 ^ 6,prod2设置为7 ^ 7。
乘法数:
计算基础值:(exp / 2)-1 +(exp%2)
最终乘法:1
合计:(exp / 2)+(exp%2)
这次,我们只有7个乘法! (之前为12)。 我们可以做得更好吗?
****************************************************** *******
方法3:分而治之我们可以进一步改善这种分而治之的方法! 将13分成2个以上的部分。 由于3 ^ 2 <13 <4 ^ 2,
并且3 * 4 <13,将其分为4部分:
13 = 3 + 3 + 3 + 4
7 ^ 13 = 7 ^ 3 * 7 ^ 3 * 7 ^ 3 * 7 ^ 4
7 * 7 = 49 = 7 ^ 2
49 * 7 = 343 = 7 ^ 3
343 * 7 = 2401 = 7 ^ 4
343 * 343 = 117649 = 7 ^ 3 * 7 ^ 3 = 7 ^ 6
117649 * 343 = 40353607 = 7 ^ 6 * 7 ^ 3 = 7 ^ 9
40353607 * 2401 = 96889010407 = 7 ^ 9 * 7 ^ 4 = 7 ^ 13
该部分的代码有些棘手,因此如果很难理解,请跳过它。 困难的部分是弄清楚您需要多少部分。
Som将指数分为几个部分的示例:
exp = 10,10:3,3,4
exp = 11,11:3,4,4
exp = 12,12:3,3,3,3(以这种方式选择,而不是4,4,4。更易于编码)
exp = 13,13:3,3,3,4
exp = 14、14:3、3、4、4
exp = 15,15:3,4,4,4
等等...
long pow(long n, long exp){
long sqroot = (long)(Math.sqrt(exp)); // truncates answer
long parts; // number of terms we need
long power; // current power
long prod; // to hold n^sqrt(exp)
long prod2; // to hold n^(sqrt(exp) + 1)
long prod3; // final answer
long terms; // number of terms remaining to be multiplied
prod = n; // hold the product of our multiplication.
for (power = 2; power <= sqroot; power ++)
{
prod *= n; //prod = n^power
}
if (exp == sqroot * sqroot) // perfect square!
prod2 = prod;
else {
prod2 = prod * n;
parts = sqroot;
if (exp >= sqroot * (sqroot + 1)){
parts++;
}
prod3 = prod; // initialize our final answer. Work backwards for a little simplicity.
//joined for loops.
for (terms = parts - 1; terms > exp % parts; terms--){
prod3 *= prod;
}
for (;terms > 0; terms--){
prod3 *= prod2;
}
return prod3;
}
乘法数:
计算基值:向下舍入sqrt(n)(如果n为平方,则为-1)
将基础值相乘:舍入sqrt(n + 0.25)-1
总乘法:大约2 * sqrt(n)
6个乘法!
****************************************************** *******
方法4:二元指数(2 ^ k元方法)现在我们仍在使用方法1来计算计算的第一部分,这很慢。 通过这种方法,我们完全消除了它。
取13的二进制数.13 = 1101的二进制数,或8 + 4 +(0)* 2 +1 = 8 + 4 +1
现在我们计算7 ^ 1、7 ^ 2、7 ^ 4、7 ^ 8。
7 = 7 ^ 1
7 * 7 = 49 = 7 ^ 1 * 7 ^ 1 = 7 ^ 2
49 * 49 = 2401 = 7 ^ 2 * 7 ^ 2 = 7 ^ 4
2401 * 2401 = 5764801 = 7 ^ 4 * 7 ^ 4 = 7 ^ 8
现在我们已经将7乘以2的幂,请注意7 ^ 13 = 7 ^ 8 * 7 ^ 4 * 7 ^ 1
5764801 * 2401 = 13841287201 = 7 ^ 8 * 7 ^ 4 = 7 ^ 12
13841287201 * 7 = 96889010407 = 7 ^ 12 * 7 = 7 ^ 13
按代码:
long pow(long n, long exp){
Vector<long> powers;
long exp2 = exp; // copy of exp
long prod = n; // holds n^2^index;
long prod2 = 1;
while (exp2 > 0){
powers.add(n);
exp2 >>= 1; // right shift 1.
prod *= prod;
}
int power = 1; // n^(2^power)
while(exp > 0){
if ((exp & 1) != 0){ // 1 bit set
prod *= powers[power];
}
power++;
exp >>= 1;
}
return prod;
}
4b:随手计算。
请注意,我们正在存储7 ^ 1、7 ^ 2、7 ^ 4、7 ^ 8。 使用这种方法,您不必存储额外的空间; 我们不断发展。 有2个数字,乘积和当前。 产品将计算我们的临时产品,而电流将计算的幂(2的幂)。
当前= 7
13是奇数,所以乘积= 7
当前= 7 * 7 = 49 = 7 ^ 2
未设置13的第二位,因此乘积保持为7。
当前= 49 * 49 = 2401 = 7 ^ 4
设置了13的第3位,因此乘积= 7 * 2401 = 16807 = 7 * 7 ^ 4 = 7 ^ 5
当前= 2401 * 2401 = 5764801 = 7 ^ 8
设置13的第4位,因此乘积= 16807 * 5764801 = 96889010407 = 7 ^ 5 * 7 ^ 8 = 7 ^ 13
按代码:
long pow(long n, long exp){
prod = 1;
while (exp > 0){
if ((exp & 1) != 0)
prod *= n;
n*=n;
exp >>= 1;
}
return prod;
}
这个例子有5个乘法。
但是,请记住,这是一个很小的指数(13)。 如果要计算一个大的指数,比如说1000,则只需要大约20个乘法! (与其他方法中至少60种相比)
乘法数:计算7 ^ 2 ^ log2(exp):log2(exp)
计算乘积:最多log2(exp)
总计:2 * log2(exp)
方法5。滑动窗口方法:这是(2 ^ k-ary)方法的有效变体。
13 = 1101(二进制)。
因此,我们采用第一个数字:1,然后是第一个2:11,然后是第3:110,最后是整个序列:1101
7 = 7 ^ 1〜1二进制
平方:
7 * 7 = 49 = 7 ^ 2〜10(二进制)
49 * 7 = 343 = 7 ^ 3〜11(二进制)
平方:
343 * 343 = 117649 = 7 ^ 6〜110(二进制)
平方:
117649 * 117649 = 13841287201 = 7 ^ 12〜1100二进制
13841287201 * 7 = 96889010407 = 7 ^ 13〜1101(二进制)
请注意,当我们对数字求平方时,它与在二进制末尾添加0相同。
如果指数的末尾为0,则可以通过乘以数字将最后一位更改为1。
代码:
long pow(long n, long exp){
long multBit = Long.HighestSetBit(exp); //used to keep track of where we are in exponent, starting at highest bit.
long prod = n;
for (multBit >>= 1; // ignore the first 1.
multBit > 0;
multBit >>=1)
{
prod *= prod;
if ((multBit & exp) != 0)
prod *= n;
}
return prod;
}
看到这种方法的YouTube的示范 乘法数
与方法4相同:最多2 log2(exp)
****************************************************** *******
乘法次数的差异
Method 1 2 3 4
exp O(n) O(n/2) O(sqrt(n)) O(log(n))
2 1 1 1 1
3 2 2 2 2
4 3 2 2 3
5 4 3 3 3
10 9 5 5 5
25 24 13 9 6
100 99 50 19 8
250 249 125 31 9
1000 999 500 62 11
2500 2499 1250 99 13
10000 9999 5000 199 15
25000 24999 12500 315 16
100000 99999 50000 631 18
250000 249999 125000 999 19
1000000 999999 500000 1999 21
一旦我们开始涉足数百万美元,那就看看它们之间的区别。
如果您的指数更大,那么您会发现它会带来不同!
希望这些技巧在需要计算诸如
30249327 ^ 30234922%3293527或
928020 ^ 329010455%781323
祝好运!
额外说明:
还有许多其他方法可以计算大指数,但这些可能是前几种基本方法。 当然,如果您的数字大于long,那么您可以替代自己的BigInt类。
如果以模块化方式使用这些方法,则可以计算每个结果的mod,结果仍将适用。 (例如,如果您正在Riemann加密方案中使用它。)
链接:
Wikipedia YouTube方法5演示标签:
幂,指数,mod,加密,大量,
翻译自: https://bytes.com/topic/algorithms/insights/886822-calculating-large-exponents
计算指数