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

发布于 2024-12-07 07:52:38 字数 137 浏览 0 评论 0原文

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

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

I am writing a program where I need to know only the first k (k can be anywhere between 1-5) numbers of another big number which can be represented as n^n where n is a very large number.

Currently I am actually calculating n^n and then parsing it as a string. I wonder if there is a better more fast method exists.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

凯凯我们等你回来 2024-12-14 07:52:38

有两种可能性。

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

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

计算 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。

There are two possibilities.

If you want the first k leading digits (as in: the leading digit of 12345 is 1), then you can use the fact that

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

so you compute the fractional part f of n*Log10(n), and then the first k digits of 10^f will be your result. This works for numbers up to about 10^10 before round-off errors start kicking in if you use double precision. For example, for n = 2^20, f = 0.57466709..., 10^f = 3.755494... so your first 5 digits are 37554. For n = 4, f = 0.4082..., 10^f = 2.56 so your first digit is 2.

If you want the first k trailing digits (as in: the trailing digit of 12345 is 5), then you can use modular arithmetic. I would use the squaring trick:

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

Taking n=2^20 as an example again, we find that result = 88576. For n=4, we have factor = 1, 4, 6 and result = 1, 1, 6 so the answer is 6.

残疾 2024-12-14 07:52:38

如果您指的是最低有效数字或最右边的数字,则可以通过模乘法来完成。它的复杂度为 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 的前三位数字。

此实现适用于小于 sqrt(INT_MAX) 的 N 值,该值会有所不同,但在我的机器和语言上它超过 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;
    }
}

if you mean the least significant or rightmost digits, this can be done with modular multiplication. It's O(N) complexity and doesn't require any special bignum data types.

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

This will print 611, the first three digits of 11^11 = 285311670611.

This implementation is suitable for values of N less than sqrt(INT_MAX), which will vary but on my machine and language it's over 46,000.

Furthermore, if it so happens that your INT_MAX is less than (10^k)^2, you can change modularExponentiation to handle any N that can fit in an int:

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

if O(n) time is insufficient for you, we can take advantage of the property of exponentiation that A^(2*C) = (A^C)^2, and get logarithmic efficiency.

//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;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文