代码之家  ›  专栏  ›  技术社区  ›  July

为什么C语言中的整数求和不正确?

c
  •  -2
  • July  · 技术社区  · 9 月前
    #include <stdio.h>
    int main(void)
    {
        unsigned sum = 0;
        for (unsigned i = 1; i <= 100000; i++)
        {
            sum += i;
        }
        printf("%lld", sum);
        return 0;
    }
    

    输出:705082704

    但正确答案应该是50000000

    3 回复  |  直到 9 月前
        1
  •  3
  •   Chris    9 月前

    您机器上的无符号整数类型几乎可以肯定是32位。这种类型可以容纳的最大数量是 4294967295 。您的预期结果大于此值,因此发生整数溢出。

    解决方案是使用更大的数据类型 sum

    如果您包括 <stdint.h> 您可能希望使用 uint64_t ,使其最大势能值为 18446744073709551615

    正如ikegami所指出的,在打印 uint64_t 价值通常而不是 %lld 你会用 %llu 。为了确保您获得正确的说明符(并且有很多),您可以包括 <inttypes.h> 并使用 PRIuN 宏族。它们列在前面链接的页面上。

    例如。

    printf("%" PRIu64 "\n", sum);
    

    如果这对C初学者来说很奇怪 PRIu64 预处理器宏插入字符串文字 "llu" ,并且编译器将相邻的字符串文字视为一个连续的字符串文字。

        2
  •  0
  •   frippe    9 月前

    出现这种行为的原因是无符号整数溢出。在C中,需要无符号整数溢出来换行(但有符号整数不是这样)。

    一切似乎都指向这样一个事实: unsigned 机器上的类型为4字节,最多可存储4个值 2^32 - 1 = 4294967295 在它缠绕之前。您可以使用检查类型的大小 sizeof(<the_type>) (即。, sizeof(unsigned) 在您的情况下)。

    在您的情况下 i 就在之前 sum 溢出是 92681 ,总计 92682 * 92681 / 2 = 4294930221 1. ,小于 4294967295 。然后添加 98682 然后得到 4294930221 + 98682 = 4295022903 ,在您的机器上无法放入无符号int,因此它包装为 4295022903 % 2^32 = 55607

    将print语句移动到for循环中,以查看它的操作。你应该看到这样的东西

    .
    .
    .
    4294559503
    4294652181
    4294744860
    4294837540
    4294930221
    55607
    148290
    240974
    333659
    426345
    519032
    611720
    .
    .
    .
    

    最后,注意你得到的结果等于 500050000 % 2^32

    ps。你可能想查一下 format specifiers 用于打印。


    1. https://en.wikipedia.org/wiki/1_%2B_2_%2B_3_%2B_4_%2B_%E2%8B%AF
        3
  •  -1
  •   Chris    9 月前

    正如你所说“但正确答案应该是50000000”,但最大值为 unsigned int 为4294967295000000000>4294967295,所以 无符号整型 无法保存结果,需要使用更大的类型,例如 unsigned long long ,该类型的最大值为18446744073709551615,大于50000000,可以让您得到正确的结果。

    运行以下代码时:

    #include <stdio.h>
    #include <limits.h>
    int main(void)
    {
        unsigned int sum = 0;
        printf("unsigned int max value is %u\n", UINT_MAX);
    
        unsigned long long  LongSum = 0;
        printf("unsigned long long value is %llu\n", ULLONG_MAX);
        for (unsigned i = 1; i <= 100000; i++)
        {
            LongSum += i;
        }
        printf("%llu\n", LongSum);
        return 0;
    }
    

    您将看到以下输出,演示使用两种不同int类型的影响。

    unsigned int max value is 4294967295
    unsigned long long value is 18446744073709551615
    5000050000