计算c中数字的大功率

时间:2015-11-26 21:40:11

标签: c

我在c中编写一个程序来存储2 ^ 100000,我使用数组来存储结果。 这是完整的代码:

public async Task<string> GetLoginProviderKeyOrNullAsync(string UserId, string Provider)
{
    var logins = await this.GetLoginsAsync(UserId);

    return logins.Where(c => c.LoginProvider == Provider)
                 .Select(c => c.ProviderKey)
                 .FirstOrDefault();
}

有人可以告诉我一种更有效的方法来减少时间复杂度吗?

3 个答案:

答案 0 :(得分:2)

二进制中的<^> 2 ^ n是一个(n + 1) - 数字整数,每个位都设置为0,除了最高有效位设置为1.例如:32 = 2 ^ 5 = 0b100000

同样,通过将归零的100001位长整数中的第100001位设置为1,可以计算计算 .O(1)与时间效率相同。

答案 1 :(得分:0)

请注意,本机C整数是有限的,实际上是与计算机字大小相关的两个幂(例如,通常为32或64位)。阅读<stdint.h>int32_t&amp; int64_t

也许你想要一些bignums(或bigints),a.k.a。arbitrary precision arithmetic

基础算法非常聪明(并且比你在学校学到的那些更高效)。所以不要试图重新发明它们,并使用像GMPlib

这样的库

答案 2 :(得分:0)

您的代码存在一些问题:

  • 数组a的大小仅为200位数。这对于2^100000位数30103来说太小了。您应该增加数组大小并检查乘法算法中的溢出。

  • 您初始化a[0] = 3;并将其评为数字1。实际上你应该写a[0] = 1;

  • 第二个循环for (i = 1; i < n; i++)应包含所需的电源号:您应该写for (i = 1; i <= n; i++)

  • 对外部循环和第二级循环使用相同的循环变量,导致行为不正确。

  • 您不测试scanf的返回值,导致无效输入的未定义行为。

  • 您不检查溢出,在大值上调用未定义的行为。

以下是更正后的版本:

#include <stdio.h>

int main()
{
    int n, i, j, x, m, test, temp;
    int a[32000];

    if (scanf("%d", &test) != 1)
        return 1;

    while (test-- > 0) {
        if (scanf("%d", &n) != 1)
            break;
        a[0] = 1;  // initializes array with only 1 digit, the number 1.
        m = 1;     // initializes digit counter
        temp = 0;  // Initializes carry variable to 0.
        for (i = 1; i <= n; i++) {
            for (j = 0; j < m; j++) {
                x = a[j] * 2 + temp; //x contains the digit by digit product
                a[j] = x % 10; //Contains the digit to store in position j
                temp = x / 10; //Contains the carry value that will be stored on later indexes
            }
            // while loop that will store the carry value on array.
            if (temp > 0) {
                if (m >= (int)(sizeof(a)/sizeof(*a)))
                    break;
                a[m++] = temp;
                temp = 0;
            }
        }
        if (temp > 0) {
            printf("overflow");
        } else {
            for (i = m - 1; i >= 0; i--) //printing answer
                putchar('0' + a[i]);
        }
        printf("\n");
    }
    return 0;
}

在我的笔记本电脑上使用输入1100000运行此代码大约需要6.5秒。这确实是非常低效的。使用一些并没有真正改变这种简单迭代算法复杂性的优化技术仍然可以产生显着的性能提升,可能<强> 100倍。

以下是一些想法:

  • 在数组中每个int存储9位数而不是1位数。

  • 在每次迭代中乘以2^29而不是2,使用long long来计算中间结果。将第一步初始化为1 << (n % 29),以使n不是29的倍数。 2^292小于10^9的最大力量。

这是实现这两个想法的版本:

#include <stdio.h>

int main() {
    int n, i, j, m, test, temp;
    int a[32000];

    if (scanf("%d", &test) != 1)
        return 1;

    while (test-- > 0) {
        if (scanf("%d", &n) != 1)
            break;
        i = n % 29;
        n /= 29;
        a[0] = 1 << i;
        m = 1;
        temp = 0;
        for (i = 1; i <= n; i++) {
            for (j = 0; j < m; j++) {
                long long x = a[j] * (1LL << 29) + temp;
                a[j] = x % 1000000000;
                temp = x / 1000000000;
            }
            if (temp > 0) {
                if (m >= (int)(sizeof(a)/sizeof(*a)))
                    break;
                a[m++] = temp;
                temp = 0;
            }
        }
        if (temp > 0) {
            printf("overflow");
        } else {
            printf("%d", a[m - 1]);
            for (i = m - 2; i >= 0; i--)
                printf("%09d", a[i]);
        }
        printf("\n");
    }
    return 0;
}

在同一台笔记本电脑上运行它只能在33毫秒内计算出正确的结果,快200倍

时间复杂性是相同的,但实施效率更高。