zoukankan      html  css  js  c++  java
  • 小学生四则运算应用软件(一)

    一、基本想法

    1、整数和分数的四则运算

            由于四则运算要支持分数,刚开始我想着是自定义分数这种数据类型,而后再重载运算符。可当整数和分数混合运算的话,就要考虑到数据类型间的转化,比较麻烦。于是我转化了下思路,即将整数看成是特殊的分数(分母为1),这样将整数和分数统一起来,那么初始化便可以根据具体的数据类型做出调整,如下图所示:

        这里需要特别注意的是,我们最后控制台显示的算式是String类型,因而要能实现分数Fraction和String直接的相互转化。

         而且要自定义一种隐式转化,这样就能令分数表示出正确的形式(比如整数10不显示分母,分数2/5等)

         这时问题又出来了,分数2/4等同于1/2,即在实际应用中分数要进行相应化简,解决方案是求取分母分子的最大公约数,并且如果分母为负数,则将分子分母同时乘以-1(为了比较大小乘以分子大小符号不会改变),如下图所示:

         最后便是运算符的重载了,这里以+、<、==为例

         其中Add函数具体实现如下:

          由于减法等同于加一个负数,除法实际上是乘一个倒数,这里就不再赘述

          另外分子不能为0,因此要进行相应的异常处理。

    2、运算符的扩展

         实际应用中四则运算不单单局限于二元运算,而是可以有多个操作符的混合运算,显然正常的算式顺序是很难计算的,这时候就应该把算式转化成逆波兰式。具体操作步骤如下:

    (1)首先把普通的表达式按照运算符分离出来放在一个集合S中,比如3+2*5 分离后集合里的元素就是 3 + 2 * 5 五个元素

    (2)再定义一个集合T(为了省去转化类型的麻烦,一般为String),主要用来存放逆波兰表达式的,除此之外需定义一个堆栈K以便存储运算符,最后从左到右遍历集合S     

     (3)遍历E的规则如下:

       (3.1)如果该元素是数字(这里是Fraction转化的String),直接把它添加到集合T中

       (3.2)否则它肯定是运算符,那么再进行判断

            (3.2.1)如果该元素是左括号,或者当时栈为空,那么直接入栈

            (3.2.2)如果该元素是右括号,则把栈内的运算符出栈并添加到集合T中,直到遇到第一个左括号结束(左括号也出栈但不添加到T)

            (3.2.3)否则该元素是普通的运算符(也就是+-*/之类的),那么用该运算符和栈内的运算符号比较优先级,如果该运算符的优先级比栈内的运算符优先级高或者栈为空,则直接入栈,否则把栈内的运算符出栈并添加到T中,再判断下个栈内的运算符优先级,直到栈内的运算符优先级<=该运算符或者栈为空时再                    把该运算符入栈

       这里运算符优先级的定义使用的是Dictionary的数据结构,如图所示:

         具体函数实现为 static Queue<object> PreOrderToPostOrder(List<string> expression),最后返回的是集合T

    计算逆波兰式的规则相应比较简单,即

    (1)从左到右遍历T

    (2)如果该元素是数字,直接入栈

    (3)如果该元素是运算符,出栈两个数,计算结果再入栈,逆波兰遍历完后栈内的元素就是表达式的值了。函数实现如下:

    3、程序流程

        目前程序设计流程为:

    (1)询问用户生成四则运算的题数

    (2)询问用户是否自己输入答案,若输入,完成后统计用户答题的正确数

    (3)询问用户是否显示正确答案

    (4)询问用户是否继续生成四则运算的题数,若否则询问是否生成题目文件,若要生成题目文件,则再询问生成题目的总题数

         从流程中可以看到程序的重中之重是要生成算式,起初我的想法是随机生成运算符(括号除外)的个数,那么表达式其实就是操作数+运算符+操作数的形式,那么相应操作数的个数其实就比运算符的个数多1,可一旦考虑到括号,数组的结构无法满足在原先算式的基础上添加括号,因而我使用的是List这一数据结构,方便插入修改。另外为了表示是操作数还是运算符,除去定义str这一List,还定义了isOperand列表(isOperand的元素为0表示为运算符,为正整数表示第几个操作数,如等于1便是第一个操作数)

         这样的话随机了括号的个数numOfBrackets,并随机括号的初始和结束位置(表示在第几个操作数前或后,即start和end),而后再将(、)插入到List str里,相应的isOperand插入-1,表示括号

            最后我们在List str首部插入通过已插入元素组合成的算式兵返回。举例2*(5+2)来说,那么str[0] = 2*(5+2),str[1]=2,str[2]=*,str[3]=5,str[4]=+,

    str[5]=2,str[6]=)。(这里space表示“ ”,主要是为了算式美观,将分数的/和除法的/区分开,另外考虑到以后可能要加负数,防止混淆)

    二、代码实现

        代码使用C#语言实现,主要包含Program.cs和Fraction.cs两个文件,前者是主程序,后者是分数类的具体实现。

    (1)Program.cs

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Linq;
      4 using System.Text;
      5 using System.Threading.Tasks;
      6 using System.IO;
      7 using Fra;
      8 
      9 
     10 namespace CalC
     11 {
     12     class Program
     13     {
     14         static Random ran = new Random();
     15         static Dictionary<string, int> priorities = null;
     16         const string operators = "+-*/=";
     17         const string space = " ";
     18         static Program()
     19         {
     20             priorities = new Dictionary<string, int>();
     21             priorities.Add("#", -1);
     22             priorities.Add("+", 0);
     23             priorities.Add("-", 0);
     24             priorities.Add("*", 1);
     25             priorities.Add("/", 1);
     26         }
     27 
     28         static void Main(string[] args)
     29         {
     30             int input = 1;
     31             while (input == 1)
     32             {
     33                 Console.Write("请输入生成四则运算题的数目: ");
     34                 int numOfQue = int.Parse(Console.ReadLine());
     35                 string[] inputAnswer = new string[numOfQue];
     36                 string[] correctAnswer = new string[numOfQue];
     37                 string[] ques = new string[numOfQue];
     38                 List<string> result = new List<string>();
     39                 for (int i = 0; i < numOfQue; i++)
     40                 {
     41                     result = produceQue();
     42                     ques[i] = result[0];
     43                     Console.Write("{0,-20}", ques[i] + operators[4]);
     44                     correctAnswer[i] = Calucate(result);
     45                 }
     46                 Console.WriteLine();
     47                 Console.Write("是否输入答案(输入1表示用户输入答案,否则不输入): ");
     48                 input = int.Parse(Console.ReadLine());
     49                 if (input == 1)
     50                 {
     51                     for (int i = 0; i < numOfQue; i++)
     52                     {
     53                         Console.Write("{0,-20}", ques[i] + operators[4] + space);
     54                         inputAnswer[i] = Console.ReadLine();
     55                     }
     56 
     57                     int numOfCorrect = 0;
     58                     for (int i = 0; i < numOfQue; i++)
     59                     {
     60                         if (inputAnswer[i] == correctAnswer[i])
     61                             numOfCorrect++;
     62                     }
     63                     Console.WriteLine("您共答对" + numOfCorrect + "道题");
     64                 }
     65 
     66 
     67                 Console.Write("是否显示正确答案(输入1表示显示正确答案,否则不显示): ");
     68                 input = int.Parse(Console.ReadLine());
     69                 if (input == 1)
     70                 {
     71                     for (int i = 0; i < numOfQue; i++)
     72                         Console.Write("{0,-20}", ques[i] + operators[4] + space + correctAnswer[i]);
     73                     Console.WriteLine();
     74                 }
     75                 Console.Write("是否继续生成四则运算题的数目(输入1继续生成,否则不生成): ");
     76                 input = int.Parse(Console.ReadLine());
     77                 Console.Clear();
     78             }
     79 
     80             Console.Write("是否生成题目文件(输入1生成,否则不生成): ");
     81             input = int.Parse(Console.ReadLine());
     82             if (input == 1)
     83             {
     84                 Console.Write("输入生成题目的数量: ");
     85                 string filename = "que.txt";//这里是你的已知文件
     86                 FileStream fs = File.Create(filename);  //创建文件
     87                 fs.Close();
     88                 StreamWriter sw = new StreamWriter(filename);
     89                 input = int.Parse(Console.ReadLine());
     90                 for (int i = 0; i < input; i++)
     91                 {
     92                     string que = "";
     93                     que = produceQue()[0];
     94                     sw.Write("{0,-20}",que + operators[4] + space);
     95                     if (i % 10 == 9)
     96                         sw.Write("
    ");
     97                 }
     98                 sw.Close();
     99             }
    100         }
    101 
    102 
    103         static List<string> produceQue()
    104         {
    105             List<string> str = new List<string>();
    106             List<int> isOperand = new List<int>();
    107             int count = 0;
    108             count = ran.Next(1, 3);
    109             int[] num = new int[count + 1];
    110             int[] den = new int[count + 1];
    111             string[] operand = new string[count + 1];
    112             int[] index = new int[count];
    113             int numOfBrackets = 0;
    114             for (int i = 0; i < count + 1; i++)
    115             {
    116                 num[i] = ran.Next(2, 5);
    117                 if (ran.Next(1, 10) < 8)
    118                     den[i] = 1;
    119                 else
    120                 {
    121                     den[i] = ran.Next(1, 5);
    122                     numOfBrackets = ran.Next(1, count);
    123                 }
    124                 operand[i] = new Fraction(num[i], den[i]).ToString();
    125                 if (i < count)
    126                     index[i] = ran.Next(0, 4);
    127             }
    128             int[] start = new int[numOfBrackets];
    129             int[] end = new int[numOfBrackets];
    130             for (int i = 0; i < numOfBrackets; i++)
    131             {
    132                 start[i] = ran.Next(1, count + 1);
    133                 end[i] = ran.Next(start[i] + 1, count + 2);
    134             }
    135             int j = 1;
    136             for (int i = 0; i < count + 1; i++)
    137             {
    138                 str.Add(operand[i]);
    139                 isOperand.Add(i + 1);
    140                 if (i < count)
    141                 {
    142                     str.Add(operators[index[i]].ToString());
    143                     isOperand.Add(0);
    144                 }
    145             }
    146             for (int i = 0; i < numOfBrackets; i++)
    147             {
    148                 int left = isOperand.FindIndex(s=>s==start[i]);
    149                 str.Insert(left, "(");
    150                 isOperand.Insert(left, -1);
    151                 int right = isOperand.FindIndex(s =>s==end[i]);
    152                 str.Insert(right + 1, ")");
    153                 isOperand.Insert(right + 1, -1);
    154             }
    155             str.Insert(0, "");
    156             for (int i = 1; i < str.Count;)
    157             {
    158                 str[0] += str[i++] + space;
    159             }
    160             return str;
    161         }
    162 
    163 
    164 
    165 
    166         static string Compute(Fraction leftNum, Fraction rightNum, int op)
    167         {
    168             switch (op)
    169             {
    170                 case 0: return leftNum + rightNum;
    171                 case 1: return leftNum - rightNum;
    172                 case 2: return leftNum * rightNum;
    173                 case 3: return leftNum / rightNum;
    174                 default: return "";
    175             }
    176         }
    177 
    178         static bool IsOperator(string op)
    179         {
    180 
    181             return operators.IndexOf(op) >= 0;
    182         }
    183 
    184         static bool IsLeftAssoc(string op)
    185         {
    186             return op == "+" || op == "-" || op == "*" || op == "/" || op == "%";
    187         }
    188 
    189         static Queue<object> PreOrderToPostOrder(List<string> expression)
    190         {
    191             var result = new Queue<object>();
    192             var operatorStack = new Stack<string>();
    193             operatorStack.Push("#");
    194             string top, cur, tempChar;
    195             string tempNum;
    196 
    197             for (int i = 1; i < expression.Count; )
    198             {
    199                 cur = expression[i++];
    200                 top = operatorStack.Peek();
    201 
    202                 if (cur == "(")
    203                 {
    204                     operatorStack.Push(cur);
    205                 }
    206                 else
    207                 {
    208                     if (IsOperator(cur))
    209                     {
    210                         while (IsOperator(top) && ((IsLeftAssoc(cur) && priorities[cur] <= priorities[top])) || (!IsLeftAssoc(cur) && priorities[cur] < priorities[top]))
    211                         {
    212                             result.Enqueue(operatorStack.Pop());
    213                             top = operatorStack.Peek();
    214                         }
    215                         operatorStack.Push(cur);
    216                     }
    217                     else if (cur == ")")
    218                     {
    219                         while (operatorStack.Count > 0 && (tempChar = operatorStack.Pop()) != "(")
    220                         {
    221                             result.Enqueue(tempChar);
    222                         }
    223                     }
    224                     else
    225                     {
    226                         tempNum = cur;
    227                         result.Enqueue(tempNum);
    228                     }
    229                 }
    230             }
    231             while (operatorStack.Count > 0)
    232             {
    233                 cur = operatorStack.Pop();
    234                 if (cur == "#") continue;
    235                 if (operatorStack.Count > 0)
    236                 {
    237                     top = operatorStack.Peek();
    238                 }
    239 
    240                 result.Enqueue(cur);
    241             }
    242 
    243             return result;
    244         }
    245 
    246         static string Calucate(List<string> expression)
    247         {
    248 
    249             var rpn = PreOrderToPostOrder(expression);
    250             var operandStack = new Stack<string>();
    251             string left, right;
    252             object cur;
    253             while (rpn.Count > 0)
    254             {
    255                 cur = rpn.Dequeue();
    256                 int index = operators.IndexOf(cur.ToString());
    257 
    258                 if (index >= 0)
    259                 {
    260                     right = operandStack.Pop();
    261                     left = operandStack.Pop();
    262                     operandStack.Push(Compute(left, right, index));
    263                 }
    264                 else
    265                 {
    266                     operandStack.Push(cur.ToString());
    267                 }
    268             }
    269             return operandStack.Pop();
    270         }
    271     }
    272 }
    View Code

     (2)  Fraction.cs

      1 using System;
      2 
      3 namespace Fra
      4 {
      5     
      6     public class Fraction
      7     {
      8         
      9         long m_iNumerator;
     10         long m_iDenominator;
     11         
     12         
     13         public Fraction()
     14         {
     15             Initialize(0,1);
     16         }
     17     
     18         public Fraction(long iWholeNumber)
     19         {
     20             Initialize(iWholeNumber, 1);
     21         }
     22     
     23         public Fraction(double dDecimalValue)
     24         {
     25             Fraction temp=ToFraction(dDecimalValue);
     26             Initialize(temp.Numerator, temp.Denominator);
     27         }
     28         
     29         public Fraction(string strValue)
     30         {
     31             Fraction temp=ToFraction(strValue);
     32             Initialize(temp.Numerator, temp.Denominator);
     33         }
     34         
     35         public Fraction(long iNumerator, long iDenominator)
     36         {
     37             Initialize(iNumerator, iDenominator);
     38         }
     39         
     40         
     41         private void Initialize(long iNumerator, long iDenominator)
     42         {
     43             Numerator=iNumerator;
     44             Denominator=iDenominator;
     45             ReduceFraction(this);
     46         }
     47     
     48         
     49         public long Denominator
     50         {
     51             get
     52             {    return m_iDenominator;    }
     53             set
     54             {
     55                 if (value!=0)
     56                     m_iDenominator=value;
     57                 else
     58                     throw new FractionException("Denominator cannot be assigned a ZERO Value");
     59             }
     60         }
     61     
     62         public long Numerator
     63         {
     64             get    
     65             {    return m_iNumerator;    }
     66             set
     67             {    m_iNumerator=value;    }
     68         }
     69     
     70 
     71         public double ToDouble()
     72         {
     73             return ( (double)this.Numerator/this.Denominator );
     74         }
     75 
     76         
     77         public override string ToString()
     78         {
     79             string str;
     80             if ( this.Denominator==1 )
     81                 str=this.Numerator.ToString();
     82             else
     83                 str=this.Numerator + "/" + this.Denominator;
     84             return str;
     85         }
     86     
     87         public static Fraction ToFraction(string strValue)
     88         {
     89             int i;
     90             for (i=0;i<strValue.Length;i++)
     91                 if (strValue[i]=='/')
     92                     break;
     93             
     94             if (i==strValue.Length)        
     95                 return ( Convert.ToDouble(strValue));
     96             
     97         
     98             long iNumerator=Convert.ToInt64(strValue.Substring(0,i));
     99             long iDenominator=Convert.ToInt64(strValue.Substring(i+1));
    100             return new Fraction(iNumerator, iDenominator);
    101         }
    102         
    103         
    104         
    105         public static Fraction ToFraction(double dValue)
    106         {
    107             try
    108             {
    109                 checked
    110                 {
    111                     Fraction frac;
    112                     if (dValue%1==0)    // if whole number
    113                     {
    114                         frac=new Fraction( (long) dValue );
    115                     }
    116                     else
    117                     {
    118                         double dTemp=dValue;
    119                         long iMultiple=1;
    120                         string strTemp=dValue.ToString();
    121                         while ( strTemp.IndexOf("E")>0 )    // if in the form like 12E-9
    122                         {
    123                             dTemp*=10;
    124                             iMultiple*=10;
    125                             strTemp=dTemp.ToString();
    126                         }
    127                         int i=0;
    128                         while ( strTemp[i]!='.' )
    129                             i++;
    130                         int iDigitsAfterDecimal=strTemp.Length-i-1;
    131                         while ( iDigitsAfterDecimal>0  )
    132                         {
    133                             dTemp*=10;
    134                             iMultiple*=10;
    135                             iDigitsAfterDecimal--;
    136                         }
    137                         frac=new Fraction( (int)Math.Round(dTemp) , iMultiple );
    138                     }
    139                     return frac;
    140                 }
    141             }
    142             catch(OverflowException)
    143             {
    144                 throw new FractionException("Conversion not possible due to overflow");
    145             }
    146             catch(Exception)
    147             {
    148                 throw new FractionException("Conversion not possible");
    149             }
    150         }
    151 
    152         public static Fraction Inverse(Fraction frac1)
    153         {
    154             if (frac1.Numerator==0)
    155                 throw new FractionException("Operation not possible (Denominator cannot be assigned a ZERO Value)");
    156     
    157             long iNumerator=frac1.Denominator;
    158             long iDenominator=frac1.Numerator;
    159             return ( new Fraction(iNumerator, iDenominator));
    160         }    
    161     
    162 
    163     
    164         public static Fraction operator -(Fraction frac1)
    165         {    return ( Negate(frac1) );    }
    166                                   
    167         public static Fraction operator +(Fraction frac1, Fraction frac2)
    168         {    return ( Add(frac1 , frac2) );    }
    169     
    170         public static Fraction operator +(int iNo, Fraction frac1)
    171         {    return ( Add(frac1 , new Fraction(iNo) ) );    }
    172     
    173         public static Fraction operator +(Fraction frac1, int iNo)
    174         {    return ( Add(frac1 , new Fraction(iNo) ) );    }
    175 
    176         public static Fraction operator +(double dbl, Fraction frac1)
    177         {    return ( Add(frac1 , Fraction.ToFraction(dbl) ) );    }
    178     
    179         public static Fraction operator +(Fraction frac1, double dbl)
    180         {    return ( Add(frac1 , Fraction.ToFraction(dbl) ) );    }
    181     
    182         public static Fraction operator -(Fraction frac1, Fraction frac2)
    183         {    return ( Add(frac1 , -frac2) );    }
    184     
    185         public static Fraction operator -(int iNo, Fraction frac1)
    186         {    return ( Add(-frac1 , new Fraction(iNo) ) );    }
    187     
    188         public static Fraction operator -(Fraction frac1, int iNo)
    189         {    return ( Add(frac1 , -(new Fraction(iNo)) ) );    }
    190 
    191         public static Fraction operator -(double dbl, Fraction frac1)
    192         {    return ( Add(-frac1 , Fraction.ToFraction(dbl) ) );    }
    193     
    194         public static Fraction operator -(Fraction frac1, double dbl)
    195         {    return ( Add(frac1 , -Fraction.ToFraction(dbl) ) );    }
    196     
    197         public static Fraction operator *(Fraction frac1, Fraction frac2)
    198         {    return ( Multiply(frac1 , frac2) );    }
    199     
    200         public static Fraction operator *(int iNo, Fraction frac1)
    201         {    return ( Multiply(frac1 , new Fraction(iNo) ) );    }
    202     
    203         public static Fraction operator *(Fraction frac1, int iNo)
    204         {    return ( Multiply(frac1 , new Fraction(iNo) ) );    }
    205     
    206         public static Fraction operator *(double dbl, Fraction frac1)
    207         {    return ( Multiply(frac1 , Fraction.ToFraction(dbl) ) );    }
    208     
    209         public static Fraction operator *(Fraction frac1, double dbl)
    210         {    return ( Multiply(frac1 , Fraction.ToFraction(dbl) ) );    }
    211     
    212         public static Fraction operator /(Fraction frac1, Fraction frac2)
    213         {    return ( Multiply( frac1 , Inverse(frac2) ) );    }
    214     
    215         public static Fraction operator /(int iNo, Fraction frac1)
    216         {    return ( Multiply( Inverse(frac1) , new Fraction(iNo) ) );    }
    217     
    218         public static Fraction operator /(Fraction frac1, int iNo)
    219         {    return ( Multiply( frac1 , Inverse(new Fraction(iNo)) ) );    }
    220     
    221         public static Fraction operator /(double dbl, Fraction frac1)
    222         {    return ( Multiply( Inverse(frac1) , Fraction.ToFraction(dbl) ) );    }
    223     
    224         public static Fraction operator /(Fraction frac1, double dbl)
    225         {    return ( Multiply( frac1 , Fraction.Inverse( Fraction.ToFraction(dbl) ) ) );    }
    226 
    227         public static bool operator ==(Fraction frac1, Fraction frac2)
    228         {    return frac1.Equals(frac2);        }
    229 
    230         public static bool operator !=(Fraction frac1, Fraction frac2)
    231         {    return ( !frac1.Equals(frac2) );    }
    232 
    233         public static bool operator ==(Fraction frac1, int iNo)
    234         {    return frac1.Equals( new Fraction(iNo));    }
    235 
    236         public static bool operator !=(Fraction frac1, int iNo)
    237         {    return ( !frac1.Equals( new Fraction(iNo)) );    }
    238         
    239         public static bool operator ==(Fraction frac1, double dbl)
    240         {    return frac1.Equals( new Fraction(dbl));    }
    241 
    242         public static bool operator !=(Fraction frac1, double dbl)
    243         {    return ( !frac1.Equals( new Fraction(dbl)) );    }
    244         
    245         public static bool operator<(Fraction frac1, Fraction frac2)
    246         {    return frac1.Numerator * frac2.Denominator < frac2.Numerator * frac1.Denominator;    }
    247 
    248         public static bool operator>(Fraction frac1, Fraction frac2)
    249         {    return frac1.Numerator * frac2.Denominator > frac2.Numerator * frac1.Denominator;    }
    250 
    251         public static bool operator<=(Fraction frac1, Fraction frac2)
    252         {    return frac1.Numerator * frac2.Denominator <= frac2.Numerator * frac1.Denominator;    }
    253         
    254         public static bool operator>=(Fraction frac1, Fraction frac2)
    255         {    return frac1.Numerator * frac2.Denominator >= frac2.Numerator * frac1.Denominator;    }
    256         
    257         
    258         
    259         public static implicit operator Fraction(long lNo)
    260         {    return new Fraction(lNo);    }
    261         public static implicit operator Fraction(double dNo)
    262         {    return new Fraction(dNo);    }
    263         public static implicit operator Fraction(string strNo)
    264         {    return new Fraction(strNo);    }
    265 
    266         public static explicit operator double(Fraction frac)
    267         {    return frac.ToDouble();    }
    268 
    269         public static implicit operator string(Fraction frac)
    270         {    return frac.ToString();    }
    271         
    272         
    273         public override bool Equals(object obj)
    274         {
    275             Fraction frac=(Fraction)obj;
    276             return ( Numerator==frac.Numerator && Denominator==frac.Denominator);
    277         }
    278         
    279     
    280            public override int GetHashCode()
    281            {
    282             return ( Convert.ToInt32((Numerator ^ Denominator) & 0xFFFFFFFF) ) ;
    283         }
    284 
    285         
    286         private static Fraction Negate(Fraction frac1)
    287         {
    288             long iNumerator=-frac1.Numerator;
    289             long iDenominator=frac1.Denominator;
    290             return ( new Fraction(iNumerator, iDenominator) );
    291 
    292         }    
    293 
    294         private static Fraction Add(Fraction frac1, Fraction frac2)
    295         {
    296             try
    297             {
    298                 checked
    299                 {
    300                     long iNumerator=frac1.Numerator*frac2.Denominator + frac2.Numerator*frac1.Denominator;
    301                     long iDenominator=frac1.Denominator*frac2.Denominator;
    302                     return ( new Fraction(iNumerator, iDenominator) );
    303                 }
    304             }
    305             catch(OverflowException)
    306             {
    307                 throw new FractionException("Overflow occurred while performing arithemetic operation");
    308             }
    309             catch(Exception)
    310             {
    311                 throw new FractionException("An error occurred while performing arithemetic operation");
    312             }
    313         }
    314     
    315         private static Fraction Multiply(Fraction frac1, Fraction frac2)
    316         {
    317             try
    318             {
    319                 checked
    320                 {
    321                     long iNumerator=frac1.Numerator*frac2.Numerator;
    322                     long iDenominator=frac1.Denominator*frac2.Denominator;
    323                     return ( new Fraction(iNumerator, iDenominator) );
    324                 }
    325             }
    326             catch(OverflowException)
    327             {
    328                 throw new FractionException("Overflow occurred while performing arithemetic operation");
    329             }
    330             catch(Exception)
    331             {
    332                 throw new FractionException("An error occurred while performing arithemetic operation");
    333             }
    334         }
    335 
    336 
    337         private static long GCD(long iNo1, long iNo2)
    338         {
    339         
    340             if (iNo1 < 0) iNo1 = -iNo1;
    341             if (iNo2 < 0) iNo2 = -iNo2;
    342             
    343             do
    344             {
    345                 if (iNo1 < iNo2)
    346                 {
    347                     long tmp = iNo1;  
    348                     iNo1 = iNo2;
    349                     iNo2 = tmp;
    350                 }
    351                 iNo1 = iNo1 % iNo2;
    352             } while (iNo1 != 0);
    353             return iNo2;
    354         }
    355     
    356         
    357         public static void ReduceFraction(Fraction frac)
    358         {
    359             try
    360             {
    361                 if (frac.Numerator==0)
    362                 {
    363                     frac.Denominator=1;
    364                     return;
    365                 }
    366                 
    367                 long iGCD=GCD(frac.Numerator, frac.Denominator);
    368                 frac.Numerator/=iGCD;
    369                 frac.Denominator/=iGCD;
    370                 
    371                 if ( frac.Denominator<0 )    
    372                 {
    373                     frac.Numerator*=-1;
    374                     frac.Denominator*=-1;    
    375                 }
    376             } 
    377             catch(Exception exp)
    378             {
    379                 throw new FractionException("Cannot reduce Fraction: " + exp.Message);
    380             }
    381         }
    382             
    383     }    
    384     public class FractionException : Exception
    385     {
    386         public FractionException() : base()
    387         {}
    388     
    389         public FractionException(string Message) : base(Message)
    390         {}
    391         
    392         public FractionException(string Message, Exception InnerException) : base(Message, InnerException)
    393         {}
    394     }    
    395     
    396 
    397 }    
    View Code

    三、遇到bug并解决

          在代码编写的过程中,遇到层出不穷的bug,o(╯□╰)o,果然debug的过程痛苦而又刺激了。这里就拿其中非常有趣的一个bug来谈下,在生成题目的过程中,会出现下图的情况:

        怎么题目都一样呢?!这不科学,那就设置断点来查下问题出现在哪里呗,结果题目是真的不一样了。

         内心其实是崩溃拒绝的,题目一样说明随机不起作用,而在C#中Random太快产生的随机数会重复,设置断点其实是起到一个延时的作用。Random类是一个产生伪随机数字的类,它的构造函数有两种,一个是直接New Random(),另外一个是New Random(Int32),前者是根据触发那刻的系统时间做为种子,来产生一个随机数字,后者可以自己设定触发的种子,一般都是用UnCheck((Int)DateTime.Now.Ticks)做为参数种子,因此如果计算机运行速度很快,如果触发Randm函数间隔时间很短,就有可能造成产生一样的随机数,因为伪随机的数字,在Random的内部产生机制中还是有一定规律的,并非是真正意义上的完全随机。在网上查询得知解决的方案有两种:

    (1)延时的办法。

    可以采用for循环的办法,也可以采用Thread.Sleep(100);

    (2)提高随机数不重复概率的种子生成方法:

    static int GetRandomSeed( )
    {
    byte[] bytes = new byte[4];
    System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider( );
    rng.GetBytes( bytes );
    return BitConverter.ToInt32( bytes , 0 );
    }

    Random random = new Random( GetRandomSeed( ) );或者 Random sourceGen = new Random(new Guid().GetHashCode());

         可程序的运行速度快是我们追求的一个性能,设置延时总感觉因小失大,最后发现一种最简单粗暴的方式,这里提出来供大家参考指正,直接把Random初始化语句放到循环外,这里不愿节外生枝,在主程序的开头就声明:

    四、部分程序截图

            程序运行的部分截图如下:(为了美观,格式化输出如Console.Write("{0,-20}", ques[i] + operators[4]);表示向左对齐,占20个字符)

    五、程序可改进处

           程序的进度就是这样,但无可避免地也会有缺陷,接下来几周需要改进的有:

    (1)目前的整数和分数都是正数,而负数没有考虑,考虑的话会负号和减号会混淆,虽然运算符前后有空格,可如果单独给负数加括号的话,会使算式可读性变差。

    (2)目前遇到除零的问题,只是单单提及到除号紧跟着的操作数不能为零,可2 / (2-2)这种情况没有考虑,所以每次生成算式的时候,要先计算下结果,如果算式抛出异常则舍弃该算式重新生成。

    (3)目前操作数和运算符的个数、范围都是固定的几个(随机生成),以后可能会将其参数化,比如-r表示操作数的范围,-n表示运算符的个数。

    (4)目前没有考虑到用户输入异常的问题,以后要加入异常处理提醒用户正常输入。

      (5) 目前生成的算式还没有检查是否重复,虽然这种情况发生的概率很小,但还是要检测/(ㄒoㄒ)/~~。初步想法是加法和乘法的运算符邻近的两个操作数是否满足交换律。

    (6)由于括号的位置是随机生成的,这样就会出现(2+2)+ 4或者(2+3)这种无意义的括号,无意义只可意会不可言传,所以还没有想到好的解决方案。

    (7)代码优化的必要性。目前是c#语言,能否扩展成网页程序、C语言等等?

          总结下来,问题还是很多的~( ̄▽ ̄~)(~ ̄▽ ̄)~!

  • 相关阅读:
    暴躁游戏

    时间记录表格
    好好生活
    JAVA环境的配置
    Java简介
    markdown学习

    Arduino
    Arduino
  • 原文地址:https://www.cnblogs.com/bywb/p/5859547.html
Copyright © 2011-2022 走看看