【问题标题】:Integer Overflow Prevention in CC中的整数溢出预防
【发布时间】:2022-01-04 20:02:06
【问题描述】:

我刚从 CS50x 的 C 部分毕业,我想尝试在 C 中实现斐波那契数列。我在运行程序后意识到整数溢出了,使用无符号 long long 只会让我到达 F47。有什么办法可以避免溢出吗?我可以用python重新实现,但是我的电脑是个土豆,我宁愿拥有C的快速运行速度。

这是我的code

编辑:这是我的代码的原始版本:

void fibonacci(long long N, FILE *out)
{
    fprintf(out, "0\n1\n");

    if (N > 2)
    {
        for (long long z = 0, i = 0, j = 1, next = 0; z < N - 2; z++)
        {
            //Next is i + j
            next = i + j;
            //old j becomes the new i
            i = j;
            //old next becomes the new j
            j = next;
            //Print j (the old next)
            fprintf(out, "%i\n", j);
        }
    }
}

该链接现在显示了我的最新版本,由于使用字符而不是整数进行添加,该版本按预期工作。

【问题讨论】:

  • “避免溢出”是指在溢出时给你一个错误并停止,还是神奇地实现不溢出的多精度算术?
  • 如果您希望代码在整数溢出时停止,请参阅 stackoverflow.com/questions/199333stackoverflow.com/questions/69104632
  • 听起来你没有正确使用unsigned long long。 64 位应该让你达到第 93 个斐波那契数左右。
  • 问题必须是独立的。您必须在问题本身中发布minimal reproducible example,而不是在可能随时腐烂的外部链接中,使问题无效
  • @RP-Lens 我们更喜欢可以在问题中看到的代码。我们希望不必追逐链接来查看您的代码。您为什么要进行编辑以使您的代码退出问题?问题中的代码更好。

标签: c integer fibonacci integer-overflow


【解决方案1】:

您的代码几乎是正确的,您应该使用fprintf(out, "%lli\n", j); 而不是%i,因为j 的类型为long long。这解释了为什么您的实现在 F47 之后失败。

long long 有 63 个值位,足够 F92 = 7540113804746346429。

使用unsigned long long 应该会得到一个额外的结果:F93 = 12200160415121876738。

在您的情况下测试溢出很容易,因为 ij 都是肯定的:

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

void fibonacci(long long N, FILE *out)
{
    fprintf(out, "0\n1\n");

    if (N > 2)
    {
        for (long long z = 0, i = 0, j = 1, next = 0; z < N - 2; z++)
        {
            if (i > LLONG_MAX - j) {
                fprintf(out, "Overflow\n");
                break;
            }
            //Next is i + j
            next = i + j;
            //old j becomes the new i
            i = j;
            //old next becomes the new j
            j = next;
            //Print j (the old next)
            fprintf(out, "%lli\n", j);
        }
    }
}

如果你想计算更大的斐波那契数,你必须使用 bignums。 C 库中没有对 bignums 的标准支持,但开源中提供了多种实现。

这是一种使用字符串处理大数的简单方法:

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

char *bignum_add(char *a, char *b) {
    size_t a_len = strlen(a), b_len = strlen(b);
    if (a_len < b_len) {
        char *c = a; a = b; b = c;
        size_t x = a_len; a_len = b_len; b_len = x;
    }
    size_t i, c_len = a_len + 1;
    char *c = malloc(c_len + 1);
    if (c == NULL) {
        fprintf(stderr, "out of memory\n");
        exit(1);
    }
    c[0] = '0';
    memcpy(c + 1, a, a_len + 1);
    for (i = 1; i <= b_len; i++) {
        if ((c[c_len - i] += b[b_len - i] - '0') > '9') {
            c[c_len - i] -= 10;
            c[c_len - i - 1]++;
        }
    }
    for (; c[c_len - i] > '9'; i++) {
        c[c_len - i] -= 10;
        c[c_len - i - 1]++;
    }
    if (c[0] == '0' && c_len > 1) {
        memmove(c, c + 1, c_len--);
    }
    return c;
}

char *fib(int n) {
    char *current = strdup("0");
    if (n > 0) {
        char *prev = current;
        current = strdup("1");
        for (int i = 1; i < n; i++) {
            printf("fib(%d) = %s\n", i, current);
            char *next = bignum_add(prev, current);
            free(prev);
            prev = current;
            current = next;
        }
        free(prev);
    }
    return current;
}

int main(int argc, char *argv[]) {
    int n = (argc > 1) ? strtol(argv[1], NULL, 0) : 100;
    char *f = fib(n);
    printf("fib(%d) = %s\n", n, f);
    free(f);
    return 0;
}

【讨论】:

    【解决方案2】:

    我在 C 语言中的一个代码中遇到了这样的问题。我必须采用 60 位数字,并且通过使用 long long int,我遇到了溢出问题。我的问题完成了使用 char 和 asci 代码 instaed int 。 我将向您展示一个在我之前的结果中添加一个很好的 int 的示例。我的 int 大于 long long int: char c; scanf("%c",&amp;c); result=result + (c - '0'); 这将支持更多数字,我认为您的代码以这种方式会做得更好。

    【讨论】:

      猜你喜欢
      • 2021-07-21
      • 2022-06-22
      • 2022-01-07
      • 2020-10-22
      • 1970-01-01
      • 1970-01-01
      • 2011-10-22
      相关资源
      最近更新 更多