使用pow()为大量

时间:2012-09-03 20:56:16

标签: c++ type-conversion

我正在尝试解决问题,其中一部分需要我计算(2 ^ n)%1000000007,其中n <= 10 ^ 9。但是我的下面的代码给出了输出“0”,即使是像n = 99这样的输入。

除了有一个循环,每次都将输出多次输出2并且每次都找到模数时(不是我正在寻找,因为这对于大数字来说会非常慢)。

#include<stdio.h>
#include<math.h>
#include<iostream>
using namespace std;
int main()
{
    unsigned long long gaps,total;
    while(1)
    {
        cin>>gaps;
        total=(unsigned long long)powf(2,gaps)%1000000007;
        cout<<total<<endl;
    }
}

5 个答案:

答案 0 :(得分:2)

你需要一个“大数”库,不清楚你在哪个平台,但从这里开始: http://gmplib.org/

答案 1 :(得分:2)

  

这不是我要找的,因为这对于大数字来说会非常慢

使用bigint库的速度会比任何其他解决方案慢很多。

不要在每次通过循环时取模数:相反,只有在输出变得大于模数时才接受它,如下所示:

#include <iostream>

int main() {
    int modulus = 1000000007;
    int n = 88888888;
    long res = 1;
    for(long i=0; i < n; ++i) {
        res *= 2;
        if(res > modulus)
            res %= modulus;
    }
    std::cout << res << std::endl;
}

这实际上很快:

$ time ./t
./t  1.19s user 0.00s system 99% cpu 1.197 total

我应该提一下,其工作原因是,如果 a b 等效mod m (即 a %m = b%m ),则此等式包含 a b 的多个 k (即上述等式暗示(a * k)%m =(b * k)%m )。

答案 2 :(得分:0)

Chris 提出了GMP,但是如果你需要这样做并且想要做C ++方式,而不是C方式,并且没有不必要的复杂性,你可能只想检查this out - 它在编译时产生很少的警告,但很简单,Just Works™。

答案 3 :(得分:0)

您可以将2^n拆分为2^m的块。你需要找到:`

2^m * 2^m * ... 2^(less than m)

m应为31,适用于32位CPU。那么你的回答是:

chunk1 % k  * chunk2 * k ...    where k=1000000007

你还是O(N)。但是,你可以利用所有chunk % k除了最后一个之外都是平等的事实,你可以做到O(1)

答案 4 :(得分:0)

我写了这个函数。它的效率很低,但是可以处理大量的数据。它使用我自己制定的算法,使用类似十进制的系统将大数字存储在数组中。

mpfr2.cpp

#include "mpfr2.h"

void mpfr2::mpfr::setNumber(std::string a) {
    for (int i = a.length() - 1, j = 0; i >= 0; ++j, --i) {
        _a[j] = a[i] - '0';
    }
    res_size = a.length();
}

int mpfr2::mpfr::multiply(mpfr& a, mpfr b)
{
    mpfr ans = mpfr();
    // One by one multiply n with individual digits of res[] 
    int i = 0;
    for (i = 0; i < b.res_size; ++i)
    {
        for (int j = 0; j < a.res_size; ++j) {
            ans._a[i + j] += b._a[i] * a._a[j];
        }
    }
    for (i = 0; i < a.res_size + b.res_size; i++)
    {
        int tmp = ans._a[i] / 10;
        ans._a[i] = ans._a[i] % 10;
        ans._a[i + 1] = ans._a[i + 1] + tmp;
    }
    for (i = a.res_size + b.res_size; i >= 0; i--)
    {
        if (ans._a[i] > 0) break;
    }
    ans.res_size = i+1;
    a = ans;
    return a.res_size;
}

mpfr2::mpfr mpfr2::mpfr::pow(mpfr a, mpfr b) {
    mpfr t = a;
    std::string bStr = "";
    for (int i = b.res_size - 1; i >= 0; --i) {
        bStr += std::to_string(b._a[i]);
    }

    int i = 1;
    while (!0) {
        if (bStr == std::to_string(i)) break;
        a.res_size = multiply(a, t);

        // Debugging
        std::cout << "\npow() iteration " << i << std::endl;
        ++i;
    }
    return a;
}

mpfr2.h

#pragma once
//#infdef MPFR2_H
//#define MPFR2_H
// C standard includes
#include <iostream>
#include <string>
#define MAX 0x7fffffff/32/4 // 2147483647
namespace mpfr2 {
    class mpfr
    {
    public:
        int _a[MAX];
        int res_size;
        void setNumber(std::string);
        static int multiply(mpfr&, mpfr);
        static mpfr pow(mpfr, mpfr);
    };
}
//#endif

main.cpp

#include <iostream>
#include <fstream>
// Local headers
#include "mpfr2.h" // Defines local mpfr algorithm library
// Namespaces
namespace m = mpfr2;     // Reduce the typing a bit later...

m::mpfr tetration(m::mpfr, int);

int main() {
// Hardcoded tests
    int x = 7;
    std::ofstream f("out.txt");
    m::mpfr t;
    for(int b=1; b<x;b++) {
        std::cout << "2^^" << b << std::endl; // Hardcoded message
        t.setNumber("2");
        m::mpfr res = tetration(t, b);
        
        for (int i = res.res_size - 1; i >= 0; i--) {
            std::cout << res._a[i];
            f << res._a[i];
        }
        f << std::endl << std::endl;
        std::cout << std::endl << std::endl;
    }

    char c; std::cin.ignore(); std::cin >> c;
    return 0;
}

m::mpfr tetration(m::mpfr a, int b)
{
    m::mpfr tmp = a;
    if (b <= 0) return m::mpfr();
    for (; b > 1; b--) tmp = m::mpfr::pow(a, tmp);
    return tmp;
}

我创建这个对象是为了四分法和最终的超手术。当数字真的很大时,可能要花很多时间才能计算出来,并且会占用大量内存。 #define MAX 0x7fffffff/32/4是一个数字可以包含的小数位数。稍后我可能会提出另一种算法,将多个数组组合成一个数字。在我的系统上,最大数组长度为0x7fffffff aka 2147486347 aka 2 ^ 31-1 aka int32_max(通常是标准int大小),因此我不得不将int32_max设置为32,以使创建此数组成为可能。我还将其划分为4,以减少multiply()函数中的内存使用。

-朱比曼