目录

  • 题目
  • 解题思路
  • 解题代码
  • 1. 错误解法
  • 2. 正确解法(1)
  • 3. 正确解法(2)
  • 4. 正确解法(3)
  • 5. 正确解法(4)

题目

循环输入,每输入一个正整数n(n ≤ 65535), 输出1 + 2 + 3 + … + n 的值,并且多输出一个空行。当没有任何输入时,结束 程序。

解题思路

我们可以通过暴力枚举或者使用等差数列前n项和的公式来计算出来结果

解题代码

1. 错误解法

# include<stdio.h>
int main()
{
	int n;
	while(scanf("%d",&n) != EOF)
	{
		int ans = n * (n + 1) / 2;
		printf("%d\n",ans);
	}
	
	return 0;
}

这里为什么出错了呢?逻辑是正确的呀?😥

这里的n是小于等于65535的,当n是65535的时候,那么n * (n + 1)已经溢出了,因为65535 可以看作是(216-1),那么可以自行计算一下n * (n + 1)的值,会大于int 所能表示的最大值231-1,所以这种方法没有考虑到溢出,所以会出错。

2. 正确解法(1)

#include <stdio.h>
int main()
{
	int n = 1;
	while(scanf("%d",&n) != EOF)
	{
		int sum = 0;//(1)
		while(n)
		{
			sum += n;
			n--;
		}
		printf("%d\n",sum);
	}
	return 0;
}
  1. sum用于存放最后的相加得到的结果

3. 正确解法(2)

#include <stdio.h>
int main()
{
	int n;
	int sum = 0;
	while(scanf("%d",&n) != EOF)
	{
		if (n % 2 == 0) //(1)
		{
			sum = n /2 * (n + 1);
		}
		else //(2)
		{
			sum = (n + 1) / 2 * n;
		}
		printf("%d\n",sum);
	}
	
	return 0;
}
  1. 如果输入的n是偶数的话,那么先计算等差数列求和公式中的n / 2,然后再乘(n + 1),这样将等差数列求和公式变一下形,那么我们就可以有效地避免错误解法中的n * (n + 1)这种溢出情况了。😎
  2. 如果输入的n是奇数的话,那么奇数加上一然后除以2,肯定得到的结果是偶数,那么我们也是将等差数列求和公式中的公式变一下形,从而有效地避免溢出。

总之,这里按照奇数和偶数分情况输出,是因为计算机中,计算除法是向下取整的,所以分奇偶情况来讨论的话,那么就不会因为计算机这种计算方法从而导致结果出错了。

4. 正确解法(3)

由于边界溢出问题,所以我们才会考虑这么多的。那么我们扩大一下存储结果的范围,那么就不用这么辛苦地考虑边界溢出问题了。
由于C语言中有无符号整型这种数据类型,它的存储范围是[0.232-1],这个题目中最大的范围是n * (n + 1),可以自己手动计算一下,n * (n + 1)的范围是小于无符号整型的最大表示范围的,所以我们可以使用无符号整型来存放结果而不用担心溢出。

#include <stdio.h>
int main()
{
	int n;
	while( scanf("%d",&n) != EOF ) 
	{
		unsigned int sum = 0;
		sum += n * (n + 1) / 2;
		printf("%u\n",sum);//(1)
	}
	return 0;
}
  1. 由于这里使用了无符号整型,那么注意输出的格式应该是%u

5. 正确解法(4)

我们可以考虑使用可以表示更大范围的数据类型来存储最后的结果,比如说这里使用 long long, long long 数据类型在C中可以表示的范围是: [- 263 , 263 -1],那么足以表示我们这道题目的结果了。

#include <stdio.h>
int main()
{
	int n;
	while( scanf("%d",&n) != EOF )
	{
		long long sum = 0;
		sum = n * (n + 1) / 2;
		printf("%lld\n",sum);//(1)
	}
	return 0;
}
  1. 这里使用了 long long 数据类型,那么注意输出格式是%lld