【问题标题】:Calculating (a^b)%MOD计算 (a^b)%MOD
【发布时间】:2012-06-30 07:48:53
【问题描述】:

我想编写计算 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 所得的余数。

【问题讨论】:

  • 只是为了澄清一下,在 C++ 中 ^ 是 XOR 运算符,而不是指数运算符(您最终会得到一些非常不合适的结果,那里有第一手经验)。我相信你必须使用Math.exp(a,b)
  • @nbrooks:虽然 C++ 使用 ^ 表示 XOR 当然是正确的,但 Math.exp(a, b) 看起来不像 C++(根据名称,我希望它能够计算指数,而不是提高一个数字的幂)。
  • 伙计们,当涉及到数字理论任务时,蛮力方法至少可以说不是解决问题的最佳方法。一点点数论 101,你就会知道经典的欧拉定理。我的答案有适当的链接。我相信 MOD 是一个适合 CPU 寄存器的常用整数,这使得该任务成为模运算中的简单练习。

标签: c++ math


【解决方案1】:

这是一个典型的任务。请(或者,真的,请!)阅读Euler's totient function

然后是Euler's theorem

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

我们在我年轻的时候手工做过这样的样本:) 即使数字远远超出 32/64 位范围。

编辑:嗯,你生活和学习。 2008年获得的结果:

"totient 是 gcd 的离散傅里叶变换:(Schramm (2008))"

所以计算 phi(b) 不需要知道它的因数。

编辑(2):

Carmichael's function 是您需要计算才能得到任何 a、b 和 MOD 的正确答案。

【讨论】:

  • 谢谢维克多。我得到了想要的。感谢您的帮助... :-) 顺便说一句,我知道 totient 函数,但不知道欧拉定理...
  • "所以计算 phi(b) 不需要知道它的因数。"不过,这看起来不像是计算 phi(b) 的实用方法。
  • @MarkDickinson:是的,这就是我添加关于 Schramm 论文的评论的原因。只涉及一个离散傅里叶变换。
  • 对不起;这就是我的意思:通过傅立叶变换计算不会比通过因式分解计算更有效。 (顺便说一句,我相信维基百科上归因于施拉姆的结果实际上要老得多。)
  • 我也相信施拉姆的结果可能早就为人所知了。傅立叶的问题......是的,我看到了我的答案的弱点。不幸的是,他不是数论家。
【解决方案2】:

我用这个函数来解决这个问题

UVA 374 - 大模组

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

// 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);
}

【讨论】:

  • 次要:角落案例失败:restOfPot(a,0, 1),可通过 long long R=1%T; 修复
【解决方案3】:

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

来自Generic Integer Operations

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

返回 bp % m。

例子:

#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;

打印:

result is: 5758534182572671080415167723795472693

【讨论】:

    【解决方案4】:

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

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

    【讨论】:

    • 这是一个数论问题,真的。这里不需要蛮力。整个任务的重点是展示一些简单的经典定理的优越性。看我的回答。
    • 有趣,猜你只是偷走了我周末的空闲时间,准备去读一读。 :)
    • 这本书不错:books.google.ru/books/about/Number_Theory.html?id=njgVUjjO-EAC Ivan Vinogradov 的书也不错。 Jean-Pierre Serre 的“Course d'arithmetique”开启了更多可能性。
    【解决方案5】:

    我建议使用专门的数学库。这看起来也像加密,所以我建议使用加密库。 GNU 一定有一个你可以使用的。这是因为在加密货币中,在许多情况下,可以选择指数以使用普通数学库无法假设的快捷方式进行有效计算。

    【讨论】:

      【解决方案6】:

      但是,b 的值可能不适合 C++ 的“long long”数据类型。例如 b 可以是第 1000000000 个斐波那契数。

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

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

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

      有时出现的另一个版本是

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

      【讨论】:

        【解决方案7】:
        #include<bits/stdc++.h>
        using namespace std;
        
        #define mod 1000000007
        #define ll long long
        
        ll power(ll x, ll y)
        {
            if ( y == 0)
                return 1;
            ll temp = power(x, y / 2);
            if (y % 2 == 0)
                return (temp * temp) % mod;
            else
                return (((temp * temp) % mod) * x) % mod;
        }
        ll dmod(ll x)
        {  
            return ((x + mod) % mod);
        }
        
        ll modular_power(ll x, ll y)
        {
            ll ans = 1;
            while (y)
            {
                if (y & 1)ans = dmod(ans * x);
                y /= 2;
                x = dmod(x * x);
            }
            return ans;
        }
        
        int main()
        { 
            ll a, b;
            cin >> a >> b;
            ll ans1 = modular_power(a, b);
            ll ans2 = power(a, b);
            //  both answers are same
            cout << ans1 << " " << ans2 ;
        }
        

        【讨论】:

        • 你能总结一下你所做的解决方案吗?
        猜你喜欢
        • 2012-01-19
        • 1970-01-01
        • 1970-01-01
        • 2020-11-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多