有没有快速的方法来确定n ^ n上的前k个数字

时间:2011-09-30 16:33:52

标签: algorithm numerical-methods

我正在编写一个程序,我只需知道第一个k(k可以是1-5之间的任何位置)的另一个大数字的数字,可以表示为n ^ n,其中n是一个非常大的数字。

目前我实际上在计算n ^ n,然后将其解析为字符串。我想知道是否存在更快更好的方法。

2 个答案:

答案 0 :(得分:10)

有两种可能性。

如果你想要前k个前导数字(如:12345的前导数字是1),那么你可以使用这个事实

n^n = 10^(n*Log10(n))

所以你计算f的小数部分n*Log10(n),然后10^f的前k个数字就是你的结果。如果使用双精度,则在舍入错误开始之前,这适用于最大约10 ^ 10的数字。例如,对于n = 2^20f = 0.57466709...10^f = 3.755494...,您的前5位数字为37554.对于n = 4f = 0.4082...10^f = 2.56所以您的第一个数字是2。

如果你想要前k个尾随数字(如:12345的尾随数字是5),那么你可以使用模运算。我会用平方法:

factor = n mod 10^k
result = 1
while (n != 0) 
    if (n is odd) then result = (result * factor) mod 10^k
    factor = (factor * factor) mod 10^k
    n >>= 1

再次以n = 2 ^ 20为例,我们发现result = 88576。对于n = 4,我们有factor = 1, 4, 6result = 1, 1, 6,所以答案是6。

答案 1 :(得分:2)

如果您指的是最不重要或最右边的数字,可以使用模乘法来完成。它的O(N)复杂度并且不需要任何特殊的bignum数据类型。

#include <cmath>
#include <cstdio>

//returns ((base ^ exponent) % mod)
int modularExponentiation(int base, int exponent, int mod){
    int result = 1;
    for(int i = 0; i < exponent; i++){
        result = (result * base) % mod;
    }
    return result;
}

int firstKDigitsOfNToThePowerOfN(int k, int n){
    return modularExponentiation(n, n, pow(10, k));
}

int main(){
    int n = 11;
    int result = firstKDigitsOfNToThePowerOfN(3, n);
    printf("%d", result); 
}

这将打印611,11 ^ 11 = 285311670611的前三位数。

此实现适用于N小于sqrt(INT_MAX)的值,这些值会有所不同,但在我的机器和语言上它会超过46,000。

此外,如果您的INT_MAX小于(10 ^ k)^ 2,则可以更改modularExponentiation以处理任何适合int的N:

int modularExponentiation(int base, int exponent, int mod){
    int result = 1;
    for(int i = 0; i < exponent; i++){
        result = (result * (base % mod)) % mod; //doesn't overflow as long as mod * mod < INT_MAX
    }
    return result;
}

如果O(n)时间不足,我们可以利用取幂的性质A ^(2 * C)=(A ^ C)^ 2,并获得对数效率。

//returns ((base ^ exponent) % mod)
int modularExponentiation(int base, int exponent, int mod){
    if (exponent == 0){return 1;}
    if (exponent == 1){return base % mod;}
    if (exponent % 2 == 1){
        return ((base % mod) * modularExponentiation(base, exponent-1, mod)) % mod;
    }
    else{
        int newBase = modularExponentiation(base, exponent / 2, mod);
        return (newBase * newBase) % mod;
    }
}