第11周 上机报告 1:累加

上机题目:用各种方法求f=1-1/2!+1/3!-...+1/9!,并且要写在一个程序中。
  目的在于锻炼各种循环。
  提倡大家优先用for循环。计数型循环很方便,要习惯。
  看题目,有点难度。题目显然将大家难住了。老师有责任,给大家跨度大了。大家要快进步,中间的招数你都领教过了,只不过现在要综合起来。

  我带着大家把这个问题分解一下,由易到难解出来。

  *********************问题的解决************************
  (一)先做一个简单程序:f=1+2+...+9
  太简单了!

int main()

{

  const int n=9;   //把9定义成常变量,这是个好办法,增强可读性、可维护性,见P30,讲过

  int i,f;   //本题求值后,f为整数,所以用int型。要根据情况选数据类型。i将用于控制循环,用int

  f=0;   //赋初值很重要,也可以定义的同时初始化。有同学算出了莫名其妙的和,因为没有赋初值

  for(i=1;i<=n;i++)

    f=f+i;         //请深刻理解for有运行机制,要习惯于这种思维

  cout<<f<<endl;

}

  在这段程序中,for可以有各种其他写法,但惟有此为最佳:i控制了循环的次数(理解为何叫计数型循环)。我们将i称作为循环变量。在for(;;)中两个分号隔开的三部分中,分别只给循环变量赋初值、判断是否结束循环、循环变量调整,其余的任何操作统统放到别的地方去做。例如此处,为f赋初值放在循环前、累加的工作作为循环体。除些之外,别的写法,如

for(f=0,i=1;i<=n;i++) f=f+i;

  或

f=0,i=1;
for(;i<=n;i++) f=f+i;

  或

for(f=0,i=1;i<=n;f=f+i,i++);

  或

f=0,i=1;
for(;i<=n;)
{
  f=f+i;
  i++;
}

  之流的,还可以写出无数,都是不利于理解的写法。
  再欣赏一下正宗的for循环,想想前面的形式,那是什么东西!?

f=0;
for(i=1;i<=n;i++)
  f=f+i;

  (二)题目再变复杂些:f=1-2+3-4+...+9

int main()
{
  const int n=9;
  int i,f,sign=1;  //引入sign用于待加式子的符号变换
  f=0;   //赋初值很重要
  for(i=1;i<=n;i++)
  {                //因为循环体中将出现多条语句,加{}使之成为一条复合语句
    f=f+sign*i;
    sign=-sign;  //这个技术很重要,相比求幂,效率提高很多
  }
  cout<<f<<endl;
}

  从这个例子中,我想强调:设计程序时,每一个变量的含义必须明确,不要试图让一个变量承担过多的角色。有些同学的变量用得很乱,碰巧得到正确的结果,有时还沾沾自喜,孰料其中存在大大的隐患。

  sign变量的名字也再次告诉我们,变量起名时,要尽量起有意义的名字,尤其其中几个变量间的关系微妙时。小程序中常用n、i、f之类的,其实并不是好习惯。想想dTax、fNetIncome,何等的清楚。

  (三)还再变复杂些:f=1-1/2+1/3-1/4+...+1/9。

int main()
{
  const int n=9;
  int i,sign=1;
  double f; //为什么换类型了?算下来f是小数,还用整型那不找错吗?
  f=0;
  for(i=1;i<=n;i++)
  {
    f=f+sign*double(1)/i;  //这儿涉及类型转换,下面将深入讨论
    sign=-sign;  //sign只用作控制符号,不作他用,欣赏一下
  }
  cout<<f<<endl;
}

  关于类型,因为i为int型,如果直接1/i结果为int型,因为i≥1,从第2次循环开始(i=2),f就一直累加0了,多么可怕的一个潜在Bug。也可以写作1/double(i),但不能是double(1/i),已经求得商为0了,再double有何用,无法起死回生了。从语句整体,写成f=f+sign/double(i);更好。

  在同学学愿意将i用作double型或float型,这样f=f+sign*1/i;或f=f+sign/i;都行。但是i是用于计数的(顺便做了除数而已)这个含义将被削弱。我个人还是不赞同这样做,尽管需要进行强制类型转换。

  (四)在(二)的基础上再做次复杂化:f=1!-2!+3!-4!+...+9!
  增加一个变量a用于表示等待累加的阶乘值,显然,在累加3!时,上一循环计算得到的阶乘a为2!,a*3即是要加的3!。

int main()

{

  const int n=9;

  int i,f,a,sign=1;  //引入sign用于待加式子的符号变换

  f=0;   //累加和的初值取0

  a=1;   //累乘积的初值取1 

  for(i=1;i<=n;i++)

  {                

    a=a*i;

    f=f+sign*a;   //将阶乘加上去,不要试图将求幂也写到一个语句中,那样的程序没法读了

    sign=-sign;  

  }

  cout<<f<<endl;

}

  (五)到此应该知道:将(三)和(四)结合起来就是我们要的结果了!
  计算:f=1-1/2!+1/3!-...+1/9!

#include <iostream>

using namespace std;

int main()

{

  const int n=9;

  int i,a,sign=1;

  double f; 

  f=0;

  a=1;  //再说一点,很多同学将这两个语句写在一行,没错,但不好

  for(i=1;i<=n;i++)

  {

    a=a*i;

    f=f+sign*double(1)/a;  

    sign=-sign;  

  }

  cout<<f<<endl;

}

  *********************用while循环实现************************
  给出循环:

for(i=1;i<=n;i++)
    f=f+i;

  对应的while循环是:

i=1;
while(i<=n)
{
  f=f+i;
  i++;
}

  仍然是一个漂亮的计数!只不过将要做的事情在合适的位置上安排好罢了。
  用while实现计算f=1-1/2!+1/3!-...+1/9!的程序是

#include <iostream>

using namespace std;

int main()

{

  const int n=9;

  int i,a,sign=1;

  double f; 

  f=0;

  a=1;

  i=1; //对应原先for循环中的<表达式1>,—— for(i=1;i<=n;i++)

  while(i<=n)  //循环条件是原for循环中的<表达式2>,—— for(i=1;i<=n;i++)

  {

    a=a*i;

    f=f+sign*double(1)/a;  

    sign=-sign;

    i++;     //不要漏下原for循环中的<表达式3>,—— for(i=1;i<=n;i++)  

  }

  cout<<f<<endl;

}

  *********************用do-while循环实现************************

  给出循环:

for(i=1;i<=n;i++)
  f=f+i;

  如果能够保证循环体至少能执行1次,对应的do-while循环是:

i=1;
do
{
  f=f+i;
  i++;
}
while(i<=n);

  换汤不换药,关键在于,对这种循环的运行过程要了然于胸。
  for循环和while循环的循环体允许一次都不执行,如果循环条件一开始就不满足。而do-while循环的循环体则最少执行一行。为此,有些问题用do-while写时就有其特点了,此处不表。
  用do-while实现计算f=1-1/2!+1/3!-...+1/9!的程序是:

#include <iostream>

using namespace std;

int main()

{

  const int n=9;

  int i,a,sign=1;

  double f; 

  f=0;

  a=1;

  i=1; //循环的初始条件

  do  

  {

    a=a*i;

    f=f+sign*double(1)/a;  

    sign=-sign;

    i++;          //循环变量的变化写在循环体内

  }while(i<=n);   //确定在何条件下循环可以继续

  cout<<f<<endl;

}

  *********************将三个循环写到一个程序中完成************************
  先写错误的做法。
  错误做法1:将上述三个程序写在一个文件中

#include <iostream>

using namespace std;

int main()

{

  for...

}

#include <iostream>

using namespace std;

int main()

{

  while...

}

#include <iostream>

using namespace std;

int main()

{

  do...

}

  出这个错误的同学,从第一章开始看起,理解:
  (1)诸如下面的语句写在最前面,且不能多写

#include <iostream>
using namespace std;

  最为重要的是,main()函数是程序执行的入口,main()函数只能有一个。

  错误做法2:简单拼接,影响最大。哪些保留,哪些得去掉?

#include <iostream>

using namespace std;

int main()

{

  const int n=9;

  int i,a,sign=1;

  double f=0; //定义变量的同时初始化

  a=1;

  i=1;  

  while(i<=n)  

  {

    a=a*i;

    f=f+sign*double(1)/a;  

    sign=-sign;

    i++;     //不要漏下原for循环中的<表达式3>,—— for(i=1;i<=n;i++)  

  }

  cout<<"(1)用while循环完成: "<<f<<endl;

  int i,a,sign=1;  //应该改成sign=1: i和a不能再定义;若全不要,退出for循环时sign值为-1,下面累加的第一项就是-1了。 

  double f; // 一定要去掉,变量的定义是分配空间,已经定义过了,且其使命已经完成,可以在下面直接挪作他用

  //下面两个循环前的赋值必须有,这是出问题最多的地方!

  f=0; //如果缺这个,后面的赋值是在已经求得的结果基础上再累加的!

  a=1; //如果缺这个,for中累加的第1项是1/9!

  for(i=1;i<=n;i++) //有人将i=1也省掉了,结果是,这个循环根本不会执行,后果很严重...

  {

    a=a*i;

    f=f+sign*double(1)/a;  

    sign=-sign;  

  }

  cout<<"(2)用for循环完成: "<<f<<endl; //...如果i=1省掉,循环不执行,输出正确,但功劳属于while

  //下面哪些该留哪些不留,请思考......

  int i,a,sign=1;

  double f; 

  f=0;

  a=1;

  i=1;

  do  

  {

    a=a*i;

    f=f+sign*double(1)/a;  

    sign=-sign;

    i++;          

  }while(i<=n);   

  cout<<"(3)用do-while循环完成: "<<f<<endl;

}

  实际上,按“自顶向下,逐步求精”的思路,此任务分成三部分,做完一个再做一个,写在一个程序中,很自然的一个“顺序结构”。我现在才发现顺序结构貌似最容易,但水不浅。

  于是,正确的程序,更重要的是漂亮的程序形如:

#include <iostream>

using namespace std;

int main()

{

  const int n=9;

  int i,a,sign=1;

  double f=0; //定义变量的同时初始化

  a=1;

  i=1;  

  while(i<=n)  

  {

    a=a*i;

    f=f+sign*double(1)/a;  

    sign=-sign;

    i++;     //不要漏下原for循环中的<表达式3>,—— for(i=1;i<=n;i++)  

  }

  cout<<"(1)用while循环完成: "<<f<<endl;

  sign=1;  

  f=0; 

  a=1; 

  for(i=1;i<=n;i++) 

  {

    a=a*i;

    f=f+sign*double(1)/a;  

    sign=-sign;  

  }

  cout<<"(2)用for循环完成: "<<f<<endl; 

  sign=1;

  f=0;

  a=1;

  i=1;

  do  

  {

    a=a*i;

    f=f+sign*double(1)/a;  

    sign=-sign;

    i++;          

  }while(i<=n);   

  cout<<"(3)用do-while循环完成: "<<f<<endl;

}

  

时间: 2024-11-08 22:39:59

第11周 上机报告 1:累加的相关文章

第11周 上机报告 2:英尺到米的转换表

题目要求:编程序生成一张从英尺到米的转换表(1米大约等于3.28英尺),以方便工厂里工人师傅使用.输出形式如下图所示,第i行第j列的值vij代表i*10+j英尺对应的米数.每输出10英尺的转换表后,另起一行输出. I2M 0 1 2 3 j 5 6 7 8 9 0 0 0.3 0.61 0.91 1.22 1.52 1.83 2.13 2.44 2.74 1 3.05 3.35 3.66 3.96 4.27 4.57 4.88 5.18 5.49 5.79 2                  

C02-程序设计基础提高班(C++)第11周上机任务-运算符重载

第11周:阅读教材第10章(p314-346),掌握用运算符重载解决问题,完成第11周上机任务: (回到C02-程序设计基础提高班(C++)学习安排) [任务1]实现复数类中的运算符重载定义一个复数类重载运算符+.-.*./,使之能用于复数的加减乘除.(1)方案一:请用类的成员函数完成运算符的重载: class Complex { public: Complex(){real=0;imag=0;} Complex(double r,double i){real=r;imag=i;} Comple

第12周 上机报告 1之练习3 回文日

题目:很诱人的一个题目:2011年11月02日是一个回文日:2011 1102,我们刚刚度过!请列出近80年和近60年还有多少个回文日(假如我们能活到百岁,你和我的--).注意:一年只有12个月. 2012年11月30日新发的程序: #include <iostream> using namespace std; int main( ) { int year,month,day,y,anothery; bool is_cycle; int count=0; for(year = 2012; y

C03-Java同步实践加强班第11周上机任务

[感谢胡光老师提供题目] (回到C03-Java同步实践加强班学习安排) 1.编写一个算术测试小软件.程序组成:编写 一个Teacher类负责给出算术题目,随机给出两个整数并进行运算,并判断回答者的答案是否正确:编写一个GUI类ComputerFrame,回答者可以通过GUI看到题目并给出答案:编写一个程序执行入口运行该软件.GUI界面如下所示.  2.模拟一个信号灯的软件.在JFrame的北面添加一个下拉列表,该下拉列表有"默认无信号"."红灯"."绿灯

C02-程序设计基础提高班(C++)第9周上机任务-类和对象

第9周:阅读教材第8章(p231-262),主要内容是类和对象,学会定义类和对象解决问题,完成第9周上机任务: (回到C02-程序设计基础提高班(C++)学习安排) 实践任务: [任务1]阅读.运行下面的程序后,按要求编制新的成员函数,并增加类的功能 #include <iostream> using namespace std; class Time { public: void set_time( ); void show_time( ); private: bool is_time(in

C++程序设计-第七周上机实践项目

回到课程主页,链接:C++程序设计课程主页-2012级 本周教学内容:第1章   C++的初步知识.通过两个典型的程序(求大值和输出星号图),获得分支和循环结构程序设计的直接体验,使学生能够通过模仿,编写出类似的程序. 上机目的:初步体验分支结构和循环结构的程序设计 上机内容:(1)求两个正整数的正差值:(2)输出四个整数中的最大值:(3)输出各大式星号图. 项目1:分支结构程序设计体验 (1)阅读课件中"给两个数,求两数中的大者"例子,结合对课堂讲授内容的理解,仔细领会让计算机进行判

C02-程序设计基础提高班(C++)第7周上机任务-指针

第7周:阅读教材第6章(p164-200),主要内容是指针,完成第7周上机任务: (回到C02-程序设计基础提高班(C++)学习安排) 实践内容: 1. (数组的排序) 按模板中的要求,用指向数组的指针变量作为形式参数编写函数,完成冒泡排序.重点体会:(1)冒泡排序算法:(2)用指向数组的指针变量作为形式参数,用数组名(即数组的地址)作为实际参数,函数中对于形参的改变实质上也就是对实参对应内存单元的改变:(3)形式参数中不指定数组大小,实际数组的大小也一并作为参数传递. #include <io

2013级C++第11周(春)项目——通过继承拥有基类的资源

课程首页在:http://blog.csdn.net/sxhelijian/article/details/11890759,内有完整教学方案及资源链接 (注:本课资料由第9周直接到第11周,因为第10周是我校春假期,全校休课.春假,实际是五一.清明.端午打包一起休息,这亲戚的做法对按周安排活动的学校更好一些.) 第一部分 程序阅读 程序阅读1:  #include<iostream> using namespace std; class A { private: int x; protect

C02-程序设计基础提高班(C++)第10周上机任务-类和对象之二

第10周:阅读教材第9章(p263-313),主要内容是构造和析构函数.对象数组.对象指针.共用数据的保护等,完成第10周上机任务: (回到C02-程序设计基础提高班(C++)学习安排) 实践任务: [任务1]设计三角形类,通过增加构造函数,使对象在定义时能够进行初始化 #include<iostream> using namespace std; class Triangle {public: float perimeter(void);//计算三角形的周长 float area(void)