【问题标题】:Handling numbers in C larger than ULONG_MAX [duplicate]处理 C 中大于 ULONG_MAX 的数字 [重复]
【发布时间】:2021-02-08 21:40:26
【问题描述】:

假设我有一个 C 中的阶乘程序。在某一时刻,它最终会计算出一个大于 ULONG_MAX 的值,如 <limits.h> 中定义的那样。我对此有几个问题:

  1. 如何检查计算值是否因大于ULONG_MAX而溢出?

  2. 我是否限制用户输入以使他们无法计算n! where n! > ULONG_MAX

  3. C 是否可以处理更大的数字?

【问题讨论】:

标签: c


【解决方案1】:

这是一个小程序,用于确定在unsigned long long 中的最大阶乘数:

#include <limits.h>
#include <stdio.h>

int main(void) {
    unsigned long long int i, factorial;
    for (i = factorial = 1; factorial <= ULLONG_MAX / i; i++) {
        factorial = factorial * i;
    }
    printf("\nMaximum number is: %llu! = %llu\n", i - 1, factorial);
    return 0;
}

输出:Maximum number is: 20! = 2432902008176640000

除此之外,如果您的系统上可用,您可以使用更大的整数类型:

#include <stdio.h>

char *int128toa(char *dest, __uint128_t n) {
    int i = 0, j = 0;
    do {
        dest[i++] = '0' + (n % 10);
    } while (n /= 10);
    dest[i] = '\0';
    while (i --> j) {
        char c = dest[i];
        dest[i] = dest[j];
        dest[j++] = c;
    }
    return dest;
}

int main(void) {
    char buf1[sizeof(__uint128_t) * 4];
    char buf2[sizeof(__uint128_t) * 4];
    __uint128_t i, factorial, uint128_max = ~(__uint128_t)0;
    for (i = factorial = 1; factorial <= uint128_max / i; i++) {
        factorial = factorial * i;
    }
    printf("\nMaximum number is: %s! = %s\n",
           int128toa(buf1, i - 1), int128toa(buf2, factorial));
    return 0;
}

输出:Maximum number is: 34! = 295232799039604140847618609643520000000

这仍然是一个很小的数字。阶乘呈指数增长。

对于较大的数字,您将使用 bignum 包,其中数字在分配的数组中表示,其大小仅受可用内存限制。广泛可用的一个是 GNU 多精度包 gmp.h

这是一个计算存储为字符串的较大阶乘的简单程序:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *strrev(char *s) {
    size_t j = 0, i = strlen(s);
    while (i --> j) {
        char c = s[i];
        s[i] = s[j];
        s[j++] = c;
    }
    return s;
}

char *mulstr(char *s, int n) {
    size_t i = 0;
    int carry = 0;
    while (s[i]) {
        carry += n * (s[i] - '0');
        s[i++] = '0' + carry % 10;
        carry /= 10;
    }
    while (carry) {
        s = realloc(s, i + 2);
        s[i++] = '0' + carry % 10;
        carry /= 10;
    }
    s[i] = '\0';
    return s;
}

char *factorial(int n) {
    char *f = strdup("1");
    for (int i = 2; i <= n; i++) {
        f = mulstr(f, i);
    }
    return f;
}

int main() {
    int n = 100;
    char *p = factorial(n);
    printf("%d! = %s\n", n, strrev(p));
    free(p);
    return 0;
}

输出:

100! 4.

【讨论】:

    猜你喜欢
    • 2013-07-10
    • 1970-01-01
    • 2023-03-16
    • 1970-01-01
    • 2016-08-08
    • 2016-06-19
    • 2016-12-14
    • 1970-01-01
    相关资源
    最近更新 更多