【问题标题】:Fastest way to compute (n + 1)^j from (n^j)从 (n^j) 计算 (n + 1)^j 的最快方法
【发布时间】:2017-01-28 09:44:47
【问题描述】:

我需要为一些非常大的 k 和 j 计算 0^j, 1^j, ..., k^j (两者都在几百万的数量级)。我正在使用 GMP 来处理大整数(是的,我需要整数,因为我需要全精度)。现在,我想知道,一旦我完成了计算 n^j 的努力,是否有办法加快 (n + 1)^j 的计算,而不是从头开始?

这是我目前用来计算功率的算法:

mpz_class pow(unsigned long int b, unsigned long int e)
{
    mpz_class res = 1;
    mpz_class m = b;

    while(e)
    {
        if(e & 1)
        {
            res *= m;   
        }

        e >>= 1;
        m *= m;
    }

    return res;
}

如你所见,每次我从头开始,都需要很多时间。

【问题讨论】:

  • 你应该从5^2 = 4^2 + 3^2 >> Fibonacci开始应用动态规划,以尽量减少计算
  • 我想你把我弄丢了...?你能详细说明一下吗?
  • @Null 你的意思是像 7^2 = 6^2 + 5^2?
  • 我建议你在math.stackexchange.com 上发布这个问题。如您所见,程序员没有太多的数学意识:)
  • @Null 5^2 * 4^2 + 3^2 因为(3, 4, 5) 是毕达哥拉斯三元组..

标签: algorithm pow


【解决方案1】:

要计算n^j,为什么不找到n 的至少一个因子,比如k 执行n^j = k^j * (n/k)^j?在计算 n^j 时,k^j(n/k)^j 都应该是已知的。

但是,上述内容可能需要 O(sqrt(n)) 时间为 n。正如您在上面的代码中提到的那样,我们在O(log(j)) 时间由Exponentiation by Squaring 独立计算n^j

因此,您可以混合使用以上内容,具体取决于哪个更大:

  1. 如果n 远小于log(j),则通过因式分解计算n^j

  2. 只要知道n^j,就计算{(2*n)^j, (3*n)^j, ..., ((n-1)*n)^j, n * n^j},并将其保存在查找表中。

  3. 如果n 大于log(j) 且无法进行上述准备好的计算,请使用对数方法,然后计算上述其他相关幂。

  4. 如果n2 的纯幂(可能是const time computation),则通过移位计算j 的幂并计算相关和。

  5. 如果n 是偶数(再次计算const 时间),则使用分解方法并计算相关乘积。

上面的内容应该会很快。例如,偶数本身的识别应该将一半的幂计算转换为乘法。可以找到更多关于因式分解的经验法则,可以进一步减少计算(特别是对于可被 3、7 等整除)

【讨论】:

  • @greybeard 刚才看到了。
  • 美丽。非常感谢!
【解决方案2】:

您可能希望使用 (n+1)^j 的二项式展开为 n^j + jn^(j-1)+j(j-1)/2 * n ^(j-2) +... + 1 并记住已经计算的较低幂,并通过加法重用它们以在 O(n) 时间内计算 (n+1)^j。如果在添加每个项的同时递增地计算系数 j, j*(j-1)/2,...,这也可以在 O(n) 中完成。

【讨论】:

  • 这听起来是个不错的解决方案。可悲的是,它还需要大量的内存。按2000000^2000000 顺序排列的每个数字都需要大约8 MB 来存储,而我买不起1 TB 或RAM...
  • 那么我们可以使用2^j*((n+1)/2)^j,当n为奇数时,2^j可以通过左移计算出来。
  • 如果我们也有一些磁盘操作怎么办,我们也要优化速度吗?
猜你喜欢
  • 2022-01-13
  • 1970-01-01
  • 1970-01-01
  • 2023-02-10
  • 1970-01-01
  • 2020-12-11
  • 2013-11-14
  • 2016-07-20
  • 1970-01-01
相关资源
最近更新 更多