想要记录自己编程思维的成长所以发到博客,欢迎并且感激大家指出缺点和错误!
一、【实验构思(Conceive)】
简单复数计算器,顾名思义,实现复数简单四则运算,要实现运算,那么就要有数据输入,数据处理,最后就是结果输出(包括错误处理啥的,体现鲁棒性容错性)。
二、【实验设计(Design)】
输入则是复数,复数个数可以是大于等于两个复数,在这个程序我只做了两个复数的运算。然后,我对复数的准确概念忘得差不多了,我就百度了一下复数的概念,如下流程图,复数的结构是由虚部和实部两个部分组成,特别地,当虚部等于0时,这个复数可以视为实数,又当虚部不等于零实部等于0时,这个复数常称为纯虚数。所以,输入程序的数据可分为两个部分,实部和虚部,根据数据结构知识,我们可以把这两部分抽象出来用结构体存储。完成了对数据的存储之后,接下来就是,第二步,处理,对数据的处理,本程序中对数据的处理可分为5种吧,№1,将输入的两个部分的数据初始化为一个整体复数(存入结构体)并打印出来正确的复数形式,№2-№5就分别是四种基础运算的实现了,我将这5(实则6)种数据处理用主函数调用几种功能函数来实现。最后,结果输出,用返回函数值或者函数过程实现。
三、【实现(Implement)】
抽象数据类型实现代码:
typedef struct {
double _real;
double _imag;
} cpxNum; //定义结构体类型cpxNum表示“复数”
函数实现输入数据的复数初始化 :
//此函数实现输入数据的复数初始化
cpxNum cpnInit(cpxNum c , double r , double i){
c._real = r;
c._imag = i;
return c;
}
实现复数的打印(增加虚部打印时的正负号输出显示问题)
void cpnDisp(cpxNum c){
printf("请确认您输入后的复数或者结果是否为: ");
if(c._imag < 0)
printf("%fi%f\n\n",c._real, c._imag);
else
printf("%fi+%f\n\n", c._real, c._imag);//增加虚部正负判别输出
}
实现加减乘除(时间复杂度都为O(1))(修改除法验证 之前是错的 在测试中发现无法达到预期结果 就回头看代码 发现if()语句条件是错的)
//加法
cpxNum cpnplus(const cpxNum c1 , const cpxNum c2 ) /*实现两个复数c1, c2的减法, 差作为函数cmilus的返回值*/
{
cpxNum result;
double r, i;
r = c1._real + c2._real;
i = c1._imag + c2._imag;
result._real = r;
result._imag = i;
return result;
}
//减法
cpxNum cpnmilus(const cpxNum c1 , const cpxNum c2 )
{
cpxNum result;
double r, i;
r = c1._real - c2._real;
i = c1._imag - c2._imag;
result._real = r;
result._imag = i;
return result;
}
//乘法:(a + bi)*(c + di)=(ac - bd)+(ad + bc)i
cpxNum cpnmultiply(const cpxNum c1 , const cpxNum c2 )
{
cpxNum result;
double r, i;
r = c1._real * c2._real - c1._imag * c2._imag ;
i = c1._real * c2._imag + c1._imag * c2._real ;
result._real = r;
result._imag = i;
return result;
}
//除法
cpxNum cpndivide( cpxNum c1 , cpxNum c2 )
{
if(pow(c2._imag,2) + pow(c2._real,2)==0){ //纠错
double r,i;
cpxNum result2;
printf("第二个复数的实部与虚部平方和不能为0 \n");
printf("请重新输入 \n");
printf("请输入第二个复数的实部\n");
scanf("%lf", &r );
printf("请输入第二个复数的虚部\n");
scanf("%lf", &i );
c2 = cpnInit(c2 , r , i );
cpnDisp(c2);
}
cpxNum result;
double r, i, d;
d = pow( c2._real, 2.0 ) + pow( c2._imag, 2.0 );
r = ( c1._real * c2._real + c1._imag * c2._imag ) / d;
i = ( c1._imag * c2._real - c1._real * c2._imag ) / d;
result._real = r;
result._imag = i;
return result;
}
最后也是最重要的主函数
通过scanf()函数接收数据,用switch开关选择函数来判断四则运算,然后调用处理函数得出结果。
特别地,我再除法函数种加入了容错性判断,根据复数除法计算公式,分母不能为零,为零地话重新输入正确的第二个复数,不会崩溃。(如果没错的话)
哈哈哈,在测试结果的时候,我又发现在输入计算代码那儿可能会出错,于是又在主函数里加了一个容错判断。
【在后续的测试中,又增加了输入数据有效性的检验】
利用了scanf()函数的返回值的判断来判别是否为有效数据,并且在过程中发现使用while()会出现死循环,经过百度,知道%*c并且要fflush(stdin)及时清理缓存,可以控制不用死循环。(因为系统不会自动清理缓存中的数据,所以,在读入错误数据时,要及时清理缓存,以免造成死循环)
资料来源有效数据判断
//主函数 程序入口
int main(){
printf("************欢迎使用复数计算器**********\n");
printf("******本计算器可执行复数的四则运算******\n");
printf("*************即加减乘除运算*************\n");
printf("****************************************\n");
//可循环使用计算器
while(1){
cpxNum c1, c2, result1,result2;
double r;
double i;
int flag;
printf("请输入第一个复数的实部\n");
flag = scanf("%lf%*c", &r );
while(flag!=1){
fflush(stdin); //加入有效数据判断
printf("您输入的数据类型不正确,请重新输入!\n");
flag = scanf("%lf%*c", &r);
// fflush(stdin);
}
printf("请输入第一个复数的虚部\n");
flag = scanf("%lf%*c", &i);
while(flag!=1){
fflush(stdin);
printf("您输入的数据类型不正确,请重新输入!\n");
flag = scanf("%lf%*c", &i);
}
result1 = cpnInit(c1 , r , i );
cpnDisp(result1);
printf("请输入第二个复数的实部\n");
flag = scanf("%lf%*c", &r );
while(flag!=1){
fflush(stdin);
printf("您输入的数据类型不正确,请重新输入!\n");
flag = scanf("%lf%*c", &r );
}
printf("请输入第二个复数的虚部\n");
flag = scanf("%lf%*c", &i );
while(flag!=1){
fflush(stdin);
printf("您输入的数据类型不正确,请重新输入!\n");
flag = scanf("%lf%*c", &i );
}
result2 = cpnInit(c2 , r , i );
cpnDisp(result2);
printf("请选择您要执行的运算\n");
printf("运算1:复数加法\n");
printf("运算2:复数减法\n");
printf("运算3:复数乘法\n");
printf("运算4:复数除法\n");
int s = 0;
printf("请输入您要执行的运算代码\n");
flag = scanf("%d%*c", &s);
while( flag!=1 ){
fflush(stdin);
printf("代码不正确,请重新输入\n");
flag = scanf("%d%*c", &s);
}
cpxNum result;
switch(s){
case 1:
{
result = cpnplus( result1, result2 );
printf("结果是:\n");
cpnDisp(result);
break;
}
case 2:
{
result = cpnmilus( result1, result2 );
printf("结果是:\n");
cpnDisp(result);
break;
}
case 3:
{
result = cpnmultiply( result1, result2 );
printf("结果是:\n");
cpnDisp(result);
break;
}
case 4:
{
result = cpndivide( result1, result2 );
printf("结果是:\n");
cpnDisp(result);
break;
}
}
if(result._imag == 0)//特殊情况
printf("此复数可以视为实数\n");
}
return 0;
}
四、【测试结果(Testing)】
五、【实验总结】
设计程序思维很重要,在看了贺老师的文章后更是这样认为,每一次设计走一次这个过程,就会在脑袋里形成这种思维方式,思维只会越来越快。然后画流程图也帮助我清晰理出思路,不会想出下一步就忘了上一步,并且更具逻辑性。 设计程序最重要的阶段就是构思和设计了吧,实现和运作都是其次。程序写好后的调试修改非常重要,程序写好能运行但还是可能会出错,这时自然就会设计鲁棒性代码了,但是我认为以后应该在程序设计时就应该想到这些会出错的地方,不至于程序写好了,运行了,出错了!?然后再返回去添加容错性代码,这是不太好的,bug可以有,再者设计的时候考虑应该周全,这个错了比bug更难改正。
六、思考题或【项目运作描述(Operate)】
无
七、【源代码】
/**
author:Cyan
data:2018/10/13
**/
#include <stdio.h>
#include <math.h>
typedef struct {
double _real;
double _imag;
} cpxNum; //定义结构体类型cpxNum表示“复数”
cpxNum cpnInit(const cpxNum , double , double ); //将输入数字复数初始化
void cpnDisp(const cpxNum ); //打印所输入复数
cpxNum cpnplus(const cpxNum , const cpxNum ); //实现两个复数c1, c2的加法, 和作为函数cplus的返回值//
cpxNum cpnmilus(const cpxNum , const cpxNum ); //实现两个复数c1, c2的减法, 差作为函数cmilus的返回值//
cpxNum cpnmultiply(const cpxNum , const cpxNum ); //实现两个复数c1, c2的乘法, 积作为函数cmultiply的返回值//
cpxNum cpndivide( cpxNum, cpxNum ); //实现两个复数c1, c2的乘法, 商作为函数cdivide的返回值//
//主函数 程序入口
int main(){
printf("************欢迎使用复数计算器**********\n");
printf("******本计算器可执行复数的四则运算******\n");
printf("*************即加减乘除运算*************\n");
printf("****************************************\n");
//可循环使用计算器
while(1){
cpxNum c1, c2, result1,result2;
double r;
double i;
int flag;
printf("请输入第一个复数的实部\n");
flag = scanf("%lf%*c", &r );
while(flag!=1){
fflush(stdin); //加入有效数据判断
printf("您输入的数据类型不正确,请重新输入!\n");
flag = scanf("%lf%*c", &r);
// fflush(stdin);
}
printf("请输入第一个复数的虚部\n");
flag = scanf("%lf%*c", &i);
while(flag!=1){
fflush(stdin);
printf("您输入的数据类型不正确,请重新输入!\n");
flag = scanf("%lf%*c", &i);
}
result1 = cpnInit(c1 , r , i );
cpnDisp(result1);
printf("请输入第二个复数的实部\n");
flag = scanf("%lf%*c", &r );
while(flag!=1){
fflush(stdin);
printf("您输入的数据类型不正确,请重新输入!\n");
flag = scanf("%lf%*c", &r );
}
printf("请输入第二个复数的虚部\n");
flag = scanf("%lf%*c", &i );
while(flag!=1){
fflush(stdin);
printf("您输入的数据类型不正确,请重新输入!\n");
flag = scanf("%lf%*c", &i );
}
result2 = cpnInit(c2 , r , i );
cpnDisp(result2);
printf("请选择您要执行的运算\n");
printf("运算1:复数加法\n");
printf("运算2:复数减法\n");
printf("运算3:复数乘法\n");
printf("运算4:复数除法\n");
int s = 0;
printf("请输入您要执行的运算代码\n");
flag = scanf("%d%*c", &s);
while( flag!=1 ){
fflush(stdin);
printf("代码不正确,请重新输入\n");
flag = scanf("%d%*c", &s);
}
cpxNum result;
switch(s){
case 1:
{
result = cpnplus( result1, result2 );
printf("结果是:\n");
cpnDisp(result);
break;
}
case 2:
{
result = cpnmilus( result1, result2 );
printf("结果是:\n");
cpnDisp(result);
break;
}
case 3:
{
result = cpnmultiply( result1, result2 );
printf("结果是:\n");
cpnDisp(result);
break;
}
case 4:
{
result = cpndivide( result1, result2 );
printf("结果是:\n");
cpnDisp(result);
break;
}
}
if(result._imag == 0)//特殊情况
printf("此复数可以视为实数\n");
}
return 0;
}
//此函数实现输入数据的复数初始化
cpxNum cpnInit(cpxNum c , double r , double i){
c._real = r;
c._imag = i;
return c;
}
//此函数实现复数的打印
void cpnDisp(cpxNum c){
printf("请确认您输入后的复数或者结果是否为: ");
if(c._imag < 0)
printf("%fi%f\n\n",c._real, c._imag);
else
printf("%fi+%f\n\n", c._real, c._imag);//增加虚部正负判别输出
}
//加法
cpxNum cpnplus(const cpxNum c1 , const cpxNum c2 ) /*实现两个复数c1, c2的减法, 差作为函数cmilus的返回值*/
{
cpxNum result;
double r, i;
r = c1._real + c2._real;
i = c1._imag + c2._imag;
result._real = r;
result._imag = i;
return result;
}
//减法
cpxNum cpnmilus(const cpxNum c1 , const cpxNum c2 )
{
cpxNum result;
double r, i;
r = c1._real - c2._real;
i = c1._imag - c2._imag;
result._real = r;
result._imag = i;
return result;
}
//乘法:(a + bi)*(c + di)=(ac - bd)+(ad + bc)i
cpxNum cpnmultiply(const cpxNum c1 , const cpxNum c2 )
{
cpxNum result;
double r, i;
r = c1._real * c2._real - c1._imag * c2._imag ;
i = c1._real * c2._imag + c1._imag * c2._real ;
result._real = r;
result._imag = i;
return result;
}
//除法
cpxNum cpndivide( cpxNum c1 , cpxNum c2 )
{
if(pow(c2._imag,2) + pow(c2._real,2)==0){ //纠错
double r,i;
cpxNum result2;
printf("第二个复数的实部与虚部平方和不能为0 \n");
printf("请重新输入 \n");
printf("请输入第二个复数的实部\n");
scanf("%lf", &r );
printf("请输入第二个复数的虚部\n");
scanf("%lf", &i );
c2 = cpnInit(c2 , r , i );
cpnDisp(c2);
}
cpxNum result;
double r, i, d;
d = pow( c2._real, 2.0 ) + pow( c2._imag, 2.0 );
r = ( c1._real * c2._real + c1._imag * c2._imag ) / d;
i = ( c1._imag * c2._real - c1._real * c2._imag ) / d;
result._real = r;
result._imag = i;
return result;
}