四则运算3


设计思路:


程序包含两部分,一部分是算式的生成,一部分是栈的使用用来判断和计算结果;


算式生成,用的是调用子函数,因为每一个年级的出题要求不同所以对出题的范围加了条件限制;程序的结构框架大致为:


程序开始将字符串数组宏定义,出题的数量和选择打印的方式都进行宏定义;


            For(         )


          {


                For(      )


                {


                    a> 产生左括号;(用switch…..case语句来判断;)


                     b> 产生数字:(其中,可以有分数小数和整数的产生)


                       其中不同年级选择的范围不同;


                    c>产生右括号;(右括号的产生是用左括号的数量来限制的)


                    d>产生运算符;运算符在输出最后一位数字之后就不会执行运算符产生的程序;)


}


}


栈程序中:


将算式生成的string类型的数组,转化为char类型的,读入到栈中,然后利用字符串优先级的判断,计算函数,我们的程序中不能出现负数所以在输出结果时加了结果判断;

//组成员:禹慧慧 吕兰兰
//四则运算,在前面的基础上实现判断正误  2016.3.19
//我们的结果是如果选择dos界面,可以在界面上实现输入结果、判断正误与给出答案;如果选择txt,则打印出一份题目和一份答案
//没有控制余数,都算成了小数
#include<iostream>
#include<ctime>
#include<cmath>
#include<sstream>
#include<string>
#include<fstream>
#define MAX 1000
using namespace std;

int N;
int way;
string str[1000];
ofstream outfile("questions.txt");
ofstream outfile_1("answers.txt");


class Input
{
public:
    Input()
    {
        for( int i = 0;i < MAX;i++ )
            Str_input[i] = '\0';
    }
    char Str_input[MAX];
    void inStr(string str11)
    {
        strcpy(Str_input,str11.c_str());
    }
};

/*输出模块*/
class Output
{
public:
    Output()
    {
        result = 0;
    }
    void getRes( double res )
    {
        result = res;
    }
    void printRes(double &num_an)
    {
        num_an=result;
    }
private:
    double result;
};

/*计算用的存储结构*/
template <class Type>
class STACK{                 
private:
    Type base[MAX];
    int Size;
public:
    STACK()
    {
        Size=0;
    };
    void push(Type a)     
    {
        base[Size]=a;
        Size++;
    }
    Type pop()           
    {
        return base[--Size];
    }
    int size()
    {return Size;}
};


/*计算的模块*/
class jisuan
{
public: 
    bool shuhanshu(char);                 
    bool fuhanshu(char);                 
    int jckh(char);                  
    bool jcxsd(char *);              
    int pdyxj(char);                 
    double ToData(char*);             
    double Call(double,double,char);    
    int ppkh(char* buffer,int pos); 
    void Opr( STACK<char>&, STACK<double>&, int& ); 
    double Calculate(char*, double& );   

};
bool jisuan::shuhanshu(char ch)      
{
    return ((ch>='0'&&ch<='9')||ch=='.')?true:false;
}
bool jisuan::fuhanshu(char ch)     
{
    return (ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='#')?true:false;
}
int jisuan::jckh(char ch)
{
    if(ch=='(')
        return 1;
    if(ch==')')
        return -1;
    return 0;
}
bool jisuan::jcxsd(char *ch)
{
    int a=0;
    for(int i=0;i<strlen(ch);i++)
        if(ch[i]=='.')          
            a++;
    if(a>1)
        return false;
    return true;
}
int jisuan::pdyxj(char ch)          //符号的优先极别
{
    switch(ch)
    {
    case '+':
        return 0;
    case '-':
        return 0;
    case '*':
        return 1;
    case '/':
        return 1;
    case '#':
        return 0;
    default:
        return -1;
    }
}
double jisuan::ToData(char* ch)   //将数字转化为数值
{
    int i,j,sumn=0;
    double sum=0.0;
    if(!jcxsd(ch)) return 0.0;
    for(i=0;i<strlen(ch);i++)           
    {
        if(ch[i]!='.')
            sumn=sumn*10+(ch[i]-'0');
        else break;
    }
    if(i<strlen(ch))
        for(j=i+1;j<strlen(ch);j++)        
            sum=sum*10+(ch[j]-'0');
    sum /= pow(10.0,(double)(strlen(ch)-1-i));
    return (sum+sumn);                    
}
double jisuan::Call(double sum,double data,char ch)
{
    double ans=0.0;
    switch(ch)
    {
    case '+':
        ans=sum+data;
        break;
    case '-':
        ans=sum-data;
        break;
    case '*':
        ans=sum*data;
        break;
    case '/':
        if( data != 0.0 )
            ans=sum/data;
        else
        {
            cout<<"程序出现除0错误,终止!\n";
            system("pause");
            exit(1);
        }
        break;
    case '#':
        return 0;
    default:ans=0.0;
        break;
    }
    return ans;
}
int jisuan::ppkh(char* buffer,int pos)     //利用栈找到匹配的括号
{
    STACK<char> Temp;
    int i;
    for(i=pos;i<strlen(buffer);i++)
    {
        if(jckh(buffer[i])==1)
            Temp.push('0');
        if(jckh(buffer[i])==-1)
        {
            Temp.pop();
            if(Temp.size()==0) return i;
        }
    }
    return -1;
}
void jisuan::Opr(STACK<char>& symbol,STACK<double>& data,int& mark)
{
    double sum;
    while(symbol.size()!=0)
    {
        char tem=symbol.pop();
        int temp=pdyxj(tem);
        symbol.push(tem);
        if(temp<mark)
            break;
        else{
            sum=Call(data.pop(),data.pop(),symbol.pop());
            data.push(sum);
        }
    }
}
double jisuan::Calculate(char* buffer,double& sum)   //字符串读入和各个函数调配
{
    STACK<double> data;
    STACK<char> symbol;
    double ans;
    char temp[MAX];
    int ct=0,mark=0,tp=0;
    data.push(sum);
    while(ct<=strlen(buffer))
    {
        if(shuhanshu(buffer[ct]))            //如果是数字或小数点
        {
            while( ct < strlen(buffer) && shuhanshu(buffer[ct]) )
                temp[tp++]=buffer[ct++];
            temp[tp]='\0';
            tp=0;                         //读到非数字也非小数为止
            ans=ToData(temp);             //把读到的字符串转化为数
            data.push(ans);

            if(ct==strlen(buffer))        //已经独到字符串末尾
            {
                mark=0;
                Opr(symbol,data,mark);    
                sum=data.pop();           
                return sum;               
            }
            else{
                int mark=pdyxj(buffer[ct]);
                Opr(symbol,data,mark);     //计算
            }
        }
        else if(fuhanshu(buffer[ct]))         //如果是运算符
            symbol.push(buffer[ct++]);     //运算符入symbol栈
        else
        {
            char BF[100];int k=0;          //如果都不是,则只能是括号
            while( jckh( buffer[ct] ) != 1 && ct <= strlen(buffer) )
                BF[k++] = buffer[ct++];
            BF[k]='\0';
            if(jckh(buffer[ct])==1)       //一旦读到左括号,寻找它匹配的右括号
            {
                int i,j;
                char Temp[100];
                for(i=ct+1,j=0;i<ppkh(buffer,ct);i++,j++)
                    Temp[j]=buffer[i];     //把这对括号中的字符串存入Temp
                Temp[j]='\0';
                data.push(Calculate(Temp,sum)); 

                ct+=(strlen(Temp)+1);       
                if(ct+1==strlen(buffer))   
                {
                    mark=0;
                    Opr(symbol,data,mark);
                    sum=data.pop();
                    return sum;
                }
                else
                {
                    mark=pdyxj(buffer[ct+1]); //不是的话继续计算
                    Opr(symbol,data,mark);
                }
                ct++;                           //读入下一个字符
            }
        }
    }
    return 0.;
}
int Expression(int grade,int N)
{

    Input in;
    jisuan cl;
    Output out;
    double sum=0.0;
    double result;
    double answer;
    cout.precision(5);
    int random_a,random_b,random_c,random_e,random_f,random_g;
    int max,min;//整数
    int random_d;
    double random_h;
    
    //根据年级的不同选择每道题目的数的数量
    if(grade==2)
    {
        random_a=rand()%2+2;
        max=100;
        min=1;
    }
    if(grade==3)
    {
        random_a=rand()%3+2;
        max=500;
        min=1;
    }
    if(grade==4)
    {
        random_a=rand()%3+2;
        max=1000;
        min=1;
    }
    if(grade==5)
    {
        random_a=rand()%3+2;
        max=10000;
        min=1;
    }
    if(grade==6)
    {
        random_a=rand()%3+2;
        max=10000;
        min=1;
    }
    for(int j=0;j<N;j++)
    { 
        int flag=0;
        int count_p=0,count_q=0;//计算括号的数量
        for(int i=0;i<random_a;i++)
       {
        if(grade==2||grade==3||grade==4)
        {
            random_b=1;//只有整数计算
        }
        if(grade==5||grade==6)
        {
            random_b=rand()%3+0;
        }
        char str1[100];
        
        //左括号的产生
        if(random_a>2&&i<(random_a-1))
        {
              random_d=rand()%4+0;
              switch(random_d)//控制括号的产生
              {
                case 0:flag=0;break;
                case 1:if(i!=(random_a-1)&&i<(random_a-2)){str[j]+='(';flag=1;count_q+=1;}break;
                case 2:flag=0;break;
                case 3:if(i!=(random_a-1)&&i<(random_a-2)){str[j]+='(';flag=1;count_q+=1;}break;
                }
          }
            //random_b=rand()%3+0;//控制数字类型
            //数字的产生
            switch(random_b)
            {
                
            case 0:
                   {
                    random_h=(rand()%100)/100.0;//小数
                       random_e=rand()%10+0;
                       random_h+=random_e;
                      stringstream ss;
                      ss<<random_h;
                       str[j]+=ss.str();
                   }
                   break;
            case 1:
                {
                random_c=rand()%(max-min+1)+min;//整数
                    itoa(random_c,str1,10);
                    str[j]+=str1;
                   } break;
            case 2:
                {//分数
                do{
                    random_f=rand()%20+1;
                    random_g=rand()%10+1;
                   }while(random_g==random_f);
                int number=1;
                int m;
                if(random_g>random_f)
                {    
                     m=random_f;
                }
                else 
                { m=random_g;}
                for(int k=2;k<m+1;k++)
                {
                     if((random_g%k==0)&&(random_f%k==0))
                    {
                         number=k;
                    }
                }
                random_f=random_f/number;
                random_g=random_g/number;
                str[j]+='(';
                if(random_g==1)
                {
                     int n=0;
                     n=random_g;
                     random_g=random_f;
                     random_f=n;
                }
                itoa(random_f,str1,10);
                str[j]+=str1;
                str[j]+='/';
                itoa(random_g,str1,10);
                str[j]+=str1;
                str[j]+=')';
               }break;
            }
            //右括号的产生
           if((flag!=1)&&(count_p!=count_q))
           {
               str[j]+=')';
               count_p+=1;
           }
           if(i==(random_a-1))
           {
               if(count_p<count_q)
               {
                   for(int k=0;k<(count_q-count_p);k++)
                   str[j]+=')';
               }
            }
        if(i!=(random_a-1))
        {
            random_b=rand()%4+0;
            switch(random_b)
            {
            case 0:{str[j]+='+';}break;
            case 1:{str[j]+='-';}break;
            case 2:{str[j]+='*';}break;
            case 3:{str[j]+='/';}break;
            }
        }
     }    
       
       in.inStr(str[j]);                              //输入模块
       out.getRes( cl.Calculate(in.Str_input,sum) ); //计算模块
       out.printRes(result);
       if (result<0)
       {
           j--;
       } 
       else
       {
           
           if(way==1)
           {
           cout<<str[j]<<"="<<endl;
           cout<<"请输入答案(6位有效数字):";
           cin>>answer;
           if (answer==result)
           {
               cout<<"回答正确!"<<endl;
           }
           else
           {
               cout<<"回答错误!"<<endl;
               cout<<"正确结果为:"<<result<<endl;
           }
           }
           else
           {
               outfile<<str[j]<<"=";
               outfile<<endl;
               outfile_1<<"正确结果为:"<<result;
                outfile_1<<endl;
           }
       }
            
    }
    
    return 0;
}    


    int main()
{
    int grade;
    srand(time(0));
    cout<<"********************************************************************************"<<endl;
    cout<<"********************************************************************************"<<endl;
    cout<<"***************************欢迎使用小学四则运算出题系统*************************"<<endl;
    cout<<"********************************************************************************"<<endl;
    cout<<"*******作者:石家庄铁道大学   信1301-2     禹慧慧    吕兰兰    2016.3.19 *******"<<endl;
    cout<<"********************************************************************************"<<endl;
    cout<<"请选择打印方式:(0-TXT,1-DOS):";
    cin>>way;
    cout<<"********************************请选择年级**************************************"<<endl;
    cout<<"                                   2年级                                        "<<endl;
    cout<<"                                   3年级                                        "<<endl;
    cout<<"                                   4年级                                        "<<endl;
    cout<<"                                   5年级                                        "<<endl;
    cout<<"                                   6年级                                        "<<endl;
    cin>>grade;
        
    cout<<"请输入题目数量:";
    cin>>N;
    if(grade==2)
    {
    Expression(grade,N);
    }
    if(grade==3)
    {
        Expression(grade,N);
    }
    if(grade==4)
    {
        Expression(grade,N);
    }
    if(grade==5)
    {
        Expression(grade,N);
    }
    if(grade==6)
    {
        Expression(grade,N);
    }
    outfile.close();
    outfile_1.close();
 }






项目计划日志(单位:h)
 

听课

编写程序

阅读相关书籍

网上查找资料

日总计

周一

2

0

1

0

3

周二

0

3

 

0.5

3.5

周三

0

3

1

0

4

周四

2

6

 

1

9

周五

0

4

0

2

6

周六

0

3

 

1

4

周日

 

 

 

 

 

周总计

4

19

2

      4.5

29.5



时间记录日志:(单位:min:


日期

开始时间

结束时间

中断时间

净时间

活动

备注

星期一

1400

15:50

10

100

听课

软件工程

 

20:00

21:00

0

60

看书

构建之法

星期二

19:00

19:30

0

30

网上查找资料

 

 

20:00

23:00

0

180

编程

结对编程

星期三

15:00

22:00

180

240

编程和上网查找资料并且调试程序

结对编程

星期四

14:00

15:50

10

100

听课

软件工程

 

16:00

23:00

60

360

编程

结对编程

星期五

16:00

21:00

30

270

编程上网查找资料

结对编程

 

星期六

19:00

22:00

0

180

编程和写博客

结对编程


缺陷记录日志:


日期

编号

类型

引入阶段

排除阶段

修复时间

修复缺陷

3/17

1

20

编码

调试

20:00

括号输出错误,运算不正确

3/18

2

20

编码

调试

19:00-21:00

对栈的编写和运算结果

3/19

3

20

编码

调试

20:00-22:00

括号的丢失和语法的错误。

 

 组成员吕兰兰网址:http://www.cnblogs.com/lvlan/

posted @ 2016-03-19 21:39  我心悦你  阅读(304)  评论(3编辑  收藏  举报