「浙江理工大学ACM入队200题系列」问题 B: 零基础学C/C++12——求平均值

2022-12-07,,,,

本题是浙江理工大学ACM入队200题第二套中的B题

我们先来看一下这题的题面.


由于是比较靠前的题目,这里插一句.各位新ACMer朋友们,请一定要养成仔细耐心看题的习惯,尤其是要利用好输入和输出样例.

样例相当于给你举了个具体的例子,可以帮助你更好的理解题目
样例会告诉你输入和输出的格式,你必须要在程序里以这样的格式输入和输出,否则会出问题
样例可以在你本地写完代码之后用作测试,来检查你的代码能否正常地运行(不过样例运行正确并不代表完全对了,可能输入其他的数据会出现别的问题)


题面

题目描述

输入3个整数,求出平均值,保留3位小数

输入

输入3个整数

输出

输出平均值,保留3位小数

样例输入

2 3 4

样例输出

3.000


常见错误思路

这题看起来非常简单,相信每一位朋友看完题面以后都会有一下的思路:

    从输入流读入这3个整数
    根据平均值的定义,先把3个整数加起来,然后除以3
    将算得的结果以3位小数的格式输出(什么,你说你不会保留3位小数?先往下看后面会给出的)

于是有些朋友们给出了如下的代码(局部):

int sum = a + b + c; // 利用sum变量保存三整数和
double ave = sum / 3; // 根据平均值的定义,计算平均值
printf("%.3lf", ave); // 利用printf函数输出结果(lf前的.3表示只显示3位小数,类似的显示两位就写%.2lf,简单吧)

发现能成功通过样例,于是自信满满地提交了上去,然后迎接他的是答案错误.

可是,难道平均值不是这么求的嘛?这和数学上求解平均值的方法完全一致啊,哪里会出现问题呢?

问题就出在这些朋友完全用数学来理解C语言的运算符了.当我们把输入改成2 2 4的时候,你就会发现程序的输出是2.000而不是我们所期待的2.666.

常见错误原因解析

首先,我们明白在C中,每个数据都是具有数据类型的,比如1,2,3这种的数据类型是int,而1.1,1.0这种的数据类型是double,并且在C中各个数据类型之间还是有一定的界限的,int和double还是有一定区别的,但是我们可以对它们进行类型转换:

int可以转为double,此时会在原本的整数之后补上全为0的小数部分
double可以转为int,此时会直接去掉原本实数的小数部分,只剩下整数部分(不是四舍五入,也不是向下取整,而是直接去掉)

然后,我们回到这道题来,为何2 2 4的输出是2.000呢?稍加观察不难发现,我们的错误结果正好是正确答案的整数部分.而后面的小数部分非常像int转为double时出现的全为0的小数部分.

那么,导致此处错误的真相也已然呼之欲出了,我们写的sum / 3所得的结果是int类型(由此才只有正确答案的整数部分),随后我们把它赋值给double类型的ave变量,触发了自动转型,将其变为了一个double类型的实数,也就是我们看到的2.000了.

那为何会如此呢?这是因为在C中,除法运算符所得结果的类型是两个操作数中精度最高的类型,精度顺序大致如下:

double > long long > int > short > char

当我们将一个int型的数据去除另一个int型的数据时,根据上述类型决定规则,我们得到的结果是一个int型的数据,由此导致了上述的问题.

这个问题在实际写代码中还是比较容易犯的,一不小心就会失误直接将两个int类型的数据相除,所以各位朋友们一定要注意奥!

解决方案

明白了问题所在,如何解决呢?非常简单,既然返回的是精度最高的类型,那么我们就将其中一个数据改为double类型呗,此处有多种解决方法:

double ave = (double)sum / 3; // 利用强制转型运算符将第一个操作数转为double

double ave = sum * 1.0 / 3; // 通过乘法(其结果类型决定方式与除法一致)间接将第一个操作数转为double(注意优先级问题,不要写成sum / 3 * 1.0)

double ave = sum / 3.0; // 将常数3写成实数形式

double sum = a + b + c; // 直接将sum定义为double类型

...

上述几种方法在此处均可行,但在别的地方受限于具体情况可能只能使用其中的一种或几种,最好都理解并掌握(原理都是将一个操作数改为double类型)

参考代码

下面给出了我自己做这道题时候的完整代码:

(仅作为参考,一定要自己写一下奥,作弊没意思,害人又害己)

#include <stdio.h>

int main()
{
int a, b, c; // 定义三个变量以储存输入的三个数
scanf("%d%d%d", &a, &b, &c); // 输入三个数
int sum = a + b + c;// 利用sum变量保存三整数和
double ave = sum / 3.0; // 根据平均值的定义,计算平均值,并使结果为实数
printf("%.3lf", ave); // 利用printf函数输出结果(lf前的.3表示只显示3位小数,类似的显示两位就写%.2lf,简单吧) return 0;
}

"正是我们每天反复做的事情,最终造就了我们,优秀不是一种行为,而是一种习惯" ---亚里士多德

这篇题解就到这里了,各位朋友如果有问题欢迎到acm成员群中提问哦!

「浙江理工大学ACM入队200题系列」问题 B: 零基础学C/C++12——求平均值的相关教程结束。

《「浙江理工大学ACM入队200题系列」问题 B: 零基础学C/C++12——求平均值.doc》

下载本文的Word格式文档,以方便收藏与打印。