关于四则运算作业的初步实现

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于四则运算作业的初步实现相关的知识,希望对你有一定的参考价值。

一.实现目标

  1. 随机生成用户所要求的各种算式,且算式不重复。
  2. 数值范围由用户自由输入。
  3. 算式包含多种数据类型,包括整数,分数,实数。
  4. 可自选乘除法。
  5. 可选择是否包含括号。

二.软件假设的一些条件

  1. 用户自己可以清楚明白正数和负数的概念,真分数与假分数的概念等这些基本数学常识,不会出现用户选择了真分数确给定数据范围为[2,3]这类错误。
  2. 假设本软件不用于高端数学比赛,故在对分母设置时保证分母不超过30。

三.设计思路

  总体流程是用户先给定需求,之后程序判断需求的合法性,对于合法需求,先生成操作数,再生成运算符,判重之后合并为一个字符串输出。先对于每一项需求分类进行讨论:

  1. 乘法与除法,由于操作符的不确定性,将操作符与操作数分别处理很明显会更加清晰,只需对有无乘除这两种情况进行不同的操作符随机即可。同时需要针对操作数的数量随机不同数量的运算符。
  2. 括号,显然对于两个操作数的算式加括号毫无意义,而对于三个操作数的运算符,把运算优先级高的子式括起来也是没有意义的,故括号范围确定。
  3. 分数,先随机构造分母(分母范围为[1,30],后同),之后随机构造出一个0到1之间的实数a,根据用户所给数据范围进行放缩为b,分子的生成算式为“分子=[b*分母]”([x]为取x整数部分)。假设用户所给区间为[l,r],其中l和r为实数,则针对实数a的放缩方法为b=a*(r-l)+l。
  4. 小数,同样利用放缩的方法对随机实数处理得a,之后根据用户输入的需要小数点后k位,对实数进行处理,即a=[(int)(a*(10^k))]*1.0/(10^k)。

四.界面设计

  个人喜欢简单明了的风格,故界面仅仅只两个个五毛钱特效的窗口。初始界面具体如下图:

  技术分享

  算式选择界面:

技术分享

  当然,上图是VS中的编辑界面,真正的界面在没有选定小数时其右边两个空间是visable=false的,分数同理。

技术分享

五.结果测试

  对于每种不同情况生成30个不同的算式,这里只截取前十个。

  1.整数[-5,9]。

            技术分享

  2.假分数[1,6]+乘除

          技术分享

  3.真分数[-0.6,0.5]+括号

          技术分享

  4.小数[-23,26.4]+小数点后两位+乘除+括号

          技术分享

六.实现代码

  1.用户选择界面的代码,主要包含判断需求合法性和各种需求的标记处理等。

     public double MIN, MAX;
        public bool mulandde, bracket, fraction,decimals;
        public int frac,dec;

        public Form2()
        {
            InitializeComponent();
            groupBox1.Visible = false;
            label3.Visible = false;
            textBox3.Visible = false;
            mulandde = bracket = fraction = decimals = false;
            frac = 0;
            dec = -1;
        }

        private void checkBox4_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBox4.Checked)
            {
                groupBox1.Visible = true;
                fraction = true;
            }
            else
            {
                groupBox1.Visible = false;
                fraction = false;
            }
        }

        private void checkBox5_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBox5.Checked)
            {
                label3.Visible = true;
                textBox3.Visible = true;
                decimals = true;
            }
            else {
                label3.Visible = false;
                textBox3.Visible = false ;
                decimals = false;
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //MIN MAX
            string s = textBox1.Text;
            if (s.Length == 0)
            {
                MessageBox.Show("填写有误,请重新填写", null, MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }
            MIN = Double.Parse(s);
            s = textBox2.Text;
            if (s.Length == 0)
            {
                MessageBox.Show("填写有误,请重新填写", null, MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }
            MAX = Double.Parse(s);

            //fraction
            if (fraction && frac == 0)
            {
                MessageBox.Show("填写有误,请重新填写", null, MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }
            //decimals
            if (decimals) {
                s = textBox3.Text;
                if (s.Length == 0)
                {
                    MessageBox.Show("填写有误,请重新填写", null, MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return;
                }
                for (int i = 0; i < s.Length; i++) if (s[i] < ‘0‘ || s[i] > ‘9‘){
                    MessageBox.Show("填写有误,请重新填写", null, MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return;
                }
                dec = int.Parse(s);
            }


            
            this.Close();
        }

        private void radioButton1_CheckedChanged(object sender, EventArgs e)
        {
            if(radioButton1.Checked) frac = 1;
        }

        private void radioButton2_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButton2.Checked) frac = 2;
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            mulandde = !mulandde;
        }

        private void checkBox2_CheckedChanged(object sender, EventArgs e)
        {
            bracket = !bracket;
        }

  2.主界面的代码,主要是操作数和运算符的生成以及打印。

        const int Maxn=30;
        Form2 form;
        string[] equation;
        double[][] num;
        string[][] cnum;
        char[][] op;
        public Form1()
        {
            InitializeComponent();
            equation = new string[Maxn];
            num = new double[Maxn][];
            for (int i = 0; i < Maxn; i++)
                num[i] = new double[3];
            op = new char[Maxn][];
            for (int i = 0; i < Maxn; i++)
                op[i] = new char[2];
            cnum=new string[Maxn][];
            for (int i = 0; i < Maxn; i++)
                cnum[i] = new string[3];
        }

        private void _sort(int ith)
        {
            if (num[ith][0] < num[ith][1]) {
                double t = num[ith][0]; 
                num[ith][0] = num[ith][1]; num[ith][1] = t;
            }
            if (num[ith][2] != 0 && num[ith][1] < num[ith][2]) {
                double t = num[ith][1];
                num[ith][1] = num[ith][2]; num[ith][2] = t;
            }
            if (num[ith][0] < num[ith][1])
            {
                double t = num[ith][0];
                num[ith][0] = num[ith][1]; num[ith][1] = t;
            }
        }

        //生成题目
        private void button1_Click(object sender, EventArgs e)
        {
            while (listBox1.Items.Count != 0)
                listBox1.Items.Remove(listBox1.Items[0]);
            //模式窗体
            Random R=new Random();
            form = new Form2();
            form.ShowDialog();
            int top = 2;
            if (form.mulandde) top = 4;
            for (int i = 0; i < Maxn; i++) {
                //构造不同的操作数
                while (true)
                {
                    build_equ(i);
                    _sort(i);
                    bool flag=true;
                    for (int j = 0; j < i; j++) if (num[i][0] == num[j][0] && num[i][1] == num[j][1] && num[i][2] == num[j][2]){
                        flag = false; break;
                    }
                    if (flag) break;
                }
                //构造运算符
                int tt = R.Next(top);
                switch (tt) {
                    case 0: op[i][0] = ‘+‘; break;
                    case 1: op[i][0] = ‘-‘; break;
                    case 2: op[i][0] = ‘*‘; break;
                    case 3: op[i][0] = ‘/‘; break;
                }
                if (num[i][2] != 0)
                {
                    tt = R.Next(top);
                    switch (tt)
                    {
                        case 0: op[i][1] = ‘+‘; break;
                        case 1: op[i][1] = ‘-‘; break;
                        case 2: op[i][1] = ‘*‘; break;
                        case 3: op[i][1] = ‘/‘; break;
                    }
                }
                else {
                    op[i][1] = ‘ ‘;
                }
                if (form.bracket&&num[i][2]!=0&&R.Next(3)==1)
                {
                    char a = op[i][0], b = op[i][1];
                    if (((a == ‘+‘ || a == ‘-‘) && (b == ‘+‘ || b == ‘-‘)) || ((a == ‘*‘ || a == ‘/‘) && (b == ‘*‘ || b == ‘/‘)))
                    {
                        equation[i] = "" + cnum[i][0] + " " + op[i][0] + " ( " + cnum[i][1];
                        equation[i] += " " + op[i][1] + " " + cnum[i][2];
                        equation[i] += " ) = ";
                    }
                    else {
                        if (a == ‘+‘ || a == ‘-‘)
                        {
                            equation[i] = "( " + cnum[i][0] + " " + op[i][0] + " " + cnum[i][1];
                            equation[i] += " ) " + op[i][1] + " " + cnum[i][2];
                            equation[i] += " = ";
                        }
                        else {
                            equation[i] = "" + cnum[i][0] + " " + op[i][0] + " ( " + cnum[i][1];
                            equation[i] += " " + op[i][1] + " " + cnum[i][2];
                            equation[i] += " ) = ";
                        }
                    }
                }
                else
                {
                    equation[i] = "" + cnum[i][0] + " " + op[i][0] + " " + cnum[i][1];
                    if (cnum[i][2] != "")
                    {
                        equation[i] += " " + op[i][1] + " " + cnum[i][2];
                    }
                    equation[i] += " = ";
                }
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < Maxn; i++)
                listBox1.Items.Add(equation[i]);
            
        }
        //构造第pos个算式操作数的函数
        private void build_equ(int pos)
        {
            //test
            Random R = new Random();
            double l=form.MIN,r=form.MAX;
            if (form.fraction) {
                if (form.frac == 1)
                {
                    //真分数
                    int fz1, fz2, fm1, fm2;
                    double t;
                    fm1 = R.Next(29) + 2;
                    fm2 = R.Next(29) + 2;
                    t = R.NextDouble()*(r - l) + l;

                    num[pos][0] = t;
                    fz1 = (int)(fm1 * t);
                    t = R.NextDouble() * (r - l) + l;
                    fz2 = (int)(fm2 * t);
                    int _gcd = gcd(fz1, fm1);
                    fz1 /= _gcd;
                    fm1 /= _gcd;
                    _gcd = gcd(fz2, fm2);
                    fz2 /= _gcd;
                    fm2 /= _gcd;
                    num[pos][1] = t;
                    if(fm1<0)
                        cnum[pos][0] = "-" + fz1 + ‘/‘ + (-fm1);
                    else
                        cnum[pos][0] = "" + fz1 + ‘/‘ + fm1;
                    if(fm2<0)
                        cnum[pos][1] = "" + fz2 + ‘/‘ + (-fm2);
                    else
                        cnum[pos][1] = "" + fz2 + ‘/‘ + fm2;

                    if (R.Next(2) == 1)
                    {
                        fm1 = R.Next(19) + 2;
                        t = R.NextDouble() * (r - l) + l;
                        num[pos][2] = t;
                        fz1 = (int)(fm1 * t);
                        _gcd = gcd(fz1, fm1);
                        fz1 /= _gcd;
                        fm1 /= _gcd;
                        cnum[pos][2] = "" + fz1 + ‘/‘ + fm1;
                    }
                    else
                    {
                        num[pos][2] = 0;
                        cnum[pos][2] = "";
                    }
                }
                else {
                    //假分数
                    int fz1, fz2, fm1, fm2;
                    double t;
                    fm1 = R.Next(19) + 2;
                    fm2 = R.Next(19) + 2;
                    t = R.NextDouble() * (r - l) + l;
                    num[pos][0] = t;
                    fz1 = (int)(fm1 * t);
                    t = R.NextDouble() * (r - l) + l;
                    fz2 = (int)(fm2 * t);
                    num[pos][1] = t;
                    int _gcd = gcd(fz1, fm1);
                    fz1 /= _gcd;
                    fm1 /= _gcd;
                    _gcd = gcd(fz2, fm2);
                    fz2 /= _gcd;
                    fm2 /= _gcd;
                    if (fm1 < 0)
                        cnum[pos][0] = "-" + fz1 + ‘/‘ + (-fm1);
                    else
                        cnum[pos][0] = "" + fz1 + ‘/‘ + fm1;
                    if (fm2 < 0)
                        cnum[pos][1] = "" + fz2 + ‘/‘ + (-fm2);
                    else
                        cnum[pos][1] = "" + fz2 + ‘/‘ + fm2;

                    if (R.Next(2) == 1)
                    {
                        fm1 = R.Next(19) + 2;
                        t = R.NextDouble() * (r - l) + l;
                        num[pos][2] = t;
                        fz1 = (int)(fm1 * t);
                        _gcd = gcd(fz1, fm1);
                        fz1 /= _gcd;
                        fm1 /= _gcd;
                        cnum[pos][2] = "" + fz1 + ‘/‘ + fm1;
                    }
                    else
                    {
                        num[pos][2] = 0;
                        cnum[pos][2] = "";
                    }
                }
            }
            else if (form.decimals)
            {
                //小数
                double a, b;
                int d = 1;
                for (int i = 1; i <= form.dec; i++) d *= 10;
                a = R.NextDouble() * (r - l) + l;
                b = R.NextDouble() * (r - l) + l;
                num[pos][0] = a;
                num[pos][1] = b;
                a = (int)(a * d);
                b = (int)(b * d);
                cnum[pos][0] = "" + (a/d);
                cnum[pos][1] = "" + (b/d);
                if (R.Next(2) == 1)
                {
                    a = R.NextDouble() * (r - l) + l;
                    num[pos][2] = a;
                    a = (int)(a * d);
                    cnum[pos][2] = "" + (a/d);
                }
                else
                {
                    num[pos][2] = 0;
                    cnum[pos][2] = "";
                }
            }
            else {
                //整数
                int a, b;
                a = (int)(R.Next((int)(r - l)) + l);
                b = (int)(R.Next((int)(r - l)) + l);
                num[pos][0] = a;
                num[pos][1] = b;
                cnum[pos][0] = "" + a;
                cnum[pos][1] = "" + b;
                if (R.Next(2) == 1)
                {
                    a = (int)(R.Next((int)(r - l)) + l); ;
                    num[pos][2] = a;
                    cnum[pos][2] = "" + a;
                }
                else {
                    num[pos][2] = 0;
                    cnum[pos][2] = "";
                }

            }

            
        }

        private int gcd(int a, int b)
        {
            //求a和b最大公约数
            int r = 1;
            while (r!=0) {
                r = a % b;
                a = b; b = r;
            }
            return a;
        }

七.项目后的一些感想

  之前在学校的学习都是写一些具体的题目,其目的性和范围性都非常的强,且问题单一,而这个项目虽然仅仅是一个四则运算,但当许多小而简单的问题联系在一起的时候就会变得复杂,对问题的分析也会变得困难,其中各种制约关系在一开始对问题进行抽象时给自己带来了不小的麻烦,这些麻烦并非想不到办法,而是不知道该怎么将某些办法结合起来。也正因此,对于软件工程这一科目有了更深一层的了解,目前的认知是软件工程的核心不是解决某个具体的技术性问题,而是合理协调用户所提需求,建立便于分析维护的问题模型。有不对指出还请老师指正~~

以上是关于关于四则运算作业的初步实现的主要内容,如果未能解决你的问题,请参考以下文章

软件工程结对编程第2次作业 - 图形界面四则运算生成工具

四则运算器初步成果小结

2020-2021 恶意代码 20181230 实践作业5.2 初步动态分析

个人作业1——四则运算题目生成程序

关于代码片段的时间复杂度

01:第一次作业,生成四则运算的小程序