C - 求连续数之和的问题

时间:2021-01-21 07:47:17

标签: c loops for-loop

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

int main() {
    int start, end, i, sum = 0, temp, x, y, z;
    puts("Please enter the starting number: ");
    scanf("%d", &start);
    temp = start;
    x = start; y = start + 1;
    puts("Please enter the last number till you want to add: ");
    scanf("%d", &end);
    for (i = start; i < end; i++) {
        z = x + y;
        x = z;
        y = y + 1;
    }
    printf("The sum of the numbers starting from %d to %d is %d", temp, end, z);
}

谁能找出这段代码有什么问题?

对于较少的数字它工作正常,但是当我分配像 1 到 1000000 这样的大数字时,它不起作用,即它返回奇怪的值。

案例 1:

Please enter the starting number:
1

Please enter the last number till you want to add:
100

The sum of the numbers starting from 1 to 100 is 5050

但在这种情况下 -

情况 2:

Please enter the starting number:
1


Please enter the last number till you want to add:
1000000


The sum of the numbers starting from 1 to 1000000 is 1784293664

这种情况有什么问题?提前致谢。

7 个答案:

答案 0 :(得分:1)

您使用的 int 分别只有 -32,768 to 32,767-2,147,483,648 to 2,147,483,647 的值范围 2 byte4 byte

您应该将 unsigned long long 用于具有值范围 0 to 18,446,744,073,709,551,615 的代码。

答案 1 :(得分:1)

这是一个数据溢出的案例。

对于从 1 到 1000000 的计算示例,从 1 到 x 的连续数字之和为 x(x+1)/2,即 500.000.500.000,该值大大高于 int (2.147. 483 647)。

考虑使用 long long int,并且不要忘记,无论您的变量的字节大小如何,直到某个值,您无论如何都会溢出。

答案 2 :(得分:1)

对于大数,您必须使用 unsigned long long int 而不是 int。这里的 int 表示最多 3 位或 4 位数字的整数,但是当您输入 5 位或更多位数字时,它会给您带来奇怪的值。

答案 3 :(得分:1)

int 类型的范围不足以表示 startstop 的大值的总和值(例如 0 到 { {1}} 超过 65536)。变量 2147483647xy 应使用类型 z 定义,该类型保证表示最大为 long long (9.22E18) 或 {{1 }} 到 9223372036854775807 (1.84E19)。

此外,您计算总和的算法是复杂的,具有不必要或未使用的中间变量。简单为王!

这是修改后的版本:

unsigned long

对于正 18446744073709551615#include <stdio.h> #include <string.h> int main() { int start, end, i; long long sum; puts("Please enter the starting number: "); if (scanf("%d", &start) != 1) return 1; puts("Please enter the last number till you want to add: "); if (scanf("%d", &end) != 1) return 1; sum = 0; for (i = start; i <= end; i++) { sum = sum + i; } printf("The sum of the numbers from %d to %d is %lld\n", start, end, sum); return 0; } 值,有一个直接的公式来计算结果。您可以用以下表达式替换 start 循环:

stop

简化为:

for

如果 if (start <= stop) { // take the sum of integers from 0 to stop: stop * (stop + 1) / 2 sum = (long long)stop * (stop + 1) / 2; // subtract the sum of integers from 0 to start - 1: (start - 1) * start / 2 sum -= (long long)start * (start - 1) / 2; } else { sum = 0; } 和/或 if (start <= stop) { sum = ((long long)stop + start)(stop - start + 1) / 2; } else { sum = 0; } 可以为负,总和仍然可以直接计算为:

start

简化为:

stop

答案 4 :(得分:1)

<块引用>

求连续数之和的问题

OP 的代码反复添加并尝试大于 INT_MAX 的总和,导致结果不正确。

  1. 使用更广​​泛的类型来计算总和,例如 long longintmax_t

  2. 性能:不要使用循环。整数 [0...N] 之和为 N*(N+1)/2

相反:

//for (i = start; i < end; i++) {
//    z = x + y;
//    x = z;
//    y = y + 1;
//}

// Sum 0 to start
long long sum_start = ((long long) start + 1) * start / 2; // or (start + 1LL)*start/2;
// Sum 0 to end
long long sum_end   = ((long long) end + 1) * end / 2;

//                                                       vvvv specifier change
printf("The sum of the numbers starting from %d to %d is %lld", 
  temp, end, sum_end - (sum_start - start));

答案 5 :(得分:0)

在第二种情况下,您使用的数字大于整数数据类型的允许范围(对于 16 位架构,从 -3276832767,从 {{1} } 到 -2,147,483,648 对于 32 位架构。)这就是它导致 integer overflow 问题的原因。要解决此问题,您可以使用其他更大的数据类型,例如 2,147,483,647long int,但我建议您使用它们的未签名数据类型,即 long long intunsigned long int,如果您是不打算使用负数,因为无符号数据类型的范围从 0 开始。

答案 6 :(得分:0)

抱歉,您不知道以下计算总和的方法吗?

long sum_from_a_to_b(long a, long b)
{
    int n;
    int acc = 0;
    for (n = a; n <= b; n++)
        acc += n;
    return  acc;
}

顺便说一下,有一个更好的公式,它不需要循环:

#include <assert.h>
/* assumed that a <= b */
long sum_from_a_to_b(long a, long b)
{
    assert(a <= b);
    return b*(b + 1)/2 - a*(a - 1)/2;
}
相关问题