计算指数_计算大指数

计算指数

计算大指数

背景:这是一篇有关如何快速有效地计算大数指数的快速文章。

从基本的乘法算法开始,它随后给出了更快的算法和一些快速示例。

本文中使用的技术可用于一般数学,加密等。

在本文中,使用以下约定:

^运算符是指指数,而不是按位异或运算。 所以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

计算指数

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值