关于c ++:计算(a ^ b)%MOD

Calculating (a^b)%MOD

我想编写代码以计算pow(a,b)%MOD的值。 我使用C ++进行编码。

但是问题是b的值可能非常大。 我知道log(b)时间复杂度方法。 但是,b的值可能不适合C ++的数据类型" long long"。 例如,b可以是第1000000000个斐波那契数。 如此大的数字本身无法精确计算(在时限内)。

附言 :

  • pow(a,b)表示a * a * a * a * ... b次。
  • X%MOD是指将X除以MOD获得的余数。


这是典型的任务。请(或者,实际上,请!)阅读有关Euler的totient函数的信息。

然后是欧拉定理。

问题是您可以将a ^ b大大减少到a ^(b%phi(MOD))。是的,您将需要某种整数分解方法,但是仍然没有关于实际计算所需功效的疯狂想法。

我们在青年时期就手工进行过此类采样:)即使数字远远超出了32/64位范围。

编辑:恩,你生活和学习。在2008年获得了以下结果:

" Totient是gcd的离散傅立叶变换:(Schramm(2008))"

因此,计算phi(b)不需要知道其因素。

编辑(2):

Carmichael函数是您需要计算的函数,以便为任何a,b和MOD获得正确的答案。


我用这个功能解决这个问题

UVA 374-大模组

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=310

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// a^b % T

// with Exponentiation by squaring (http://en.wikipedia.org/wiki/Exponentiation_by_squaring#Basic_method)

// if a very large use
// R=(unsigned long long)(R*a)%T;

int restOfPot(long long a,int b,int T)
{
    a%=T;
    long long R=1;

    while(b)
    {
        if(b&1) R=(R*a)%T;
        a=(a*a)%T;
        b>>=1;
    }

    return int(R);
}


要处理非常大的数字,请查看boost的Multiprecision库。它具有一个powm()函数,可以很好地实现此目的。

来自通用整数运算:

1
2
template <class Integer>
Integer powm(const Integer& b, const Integer& p, const Integer& m);

Returns bp % m.

例:

1
2
3
4
5
6
7
8
9
#include <boost/multiprecision/cpp_int.hpp>

boost::multiprecision::cpp_int pow("8912627233012800753578052027888001981");
boost::multiprecision::cpp_int mod("0x86f71688cdd2612c117d1f54bdae029");
boost::multiprecision::cpp_int base(12345);

boost::multiprecision::cpp_int result = powm(base, pow, mod);

std::cout <<"result is:" << result << std::endl;

印刷品:

1
result is: 5758534182572671080415167723795472693

But, the value of b might not fit in the data type"long long" of C++. For example b can be 1000000000 th Fibonacci number.

对于这样的事情,有一个简单的解决方法:回想

a^(b+c) == a^b * a^c mod d

您可以使用与计算斐波那契数相同的递归来计算所要的特定产品-完全不需要大数或模幂!

有时会出现另一个版本

a^(b*c) = (a^b)^c mod d


我建议使用专门的数学库。而且这看起来像加密货币,所以我建议使用加密货币库。 GNU一定有一个您可以使用的。这是因为在很多情况下,可以使用常规数学库无法假定的快捷方式来选择指数,以进行有效的计算,从而达到加密效果。


首先:C / C ++中的^不是幂运算符。实际上,没有运算符。 ^表示按位XOR。您必须使用pow(base, exp),它可以在标题math.hcmath中找到。

对于如此巨大的数字,请使用doublelong double(确切的长度以及生成的数据类型可能会因平台而异),但是有时您会发现精度问题,因此取决于使用情况,值的大小您最好的选择可能是使用自定义数据类型(编辑:例如,从其中一个链接问题中找到的库之一)。