小學生四則運算應用軟件(一)

1、基本想法

一、整數和分數的四則運算

        因爲四則運算要支持分數,剛開始我想着是自定義分數這種數據類型,然後再重載運算符。可當整數和分數混合運算的話,就要考慮到數據類型間的轉化,比較麻煩。因而我轉化了下思路,即將整數當作是特殊的分數(分母爲1),這樣將整數和分數統一塊兒來,那麼初始化即可以根據具體的數據類型作出調整,以下圖所示:git

    這裏須要特別注意的是,咱們最後控制檯顯示的算式是String類型,於是要能實現分數Fraction和String直接的相互轉化。express

     並且要自定義一種隱式轉化,這樣就能令分數表示出正確的形式(好比整數10不顯示分母,分數2/5等)c#

     這時問題又出來了,分數2/4等同於1/2,即在實際應用中分數要進行相應化簡,解決方案是求取分母分子的最大公約數,而且若是分母爲負數,則將分子分母同時乘以-1(爲了比較大小乘以分子大小符號不會改變),以下圖所示:數組

     最後即是運算符的重載了,這裏以+、<、==爲例數據結構

     其中Add函數具體實現以下:dom

      因爲減法等同於加一個負數,除法其實是乘一個倒數,這裏就再也不贅述ide

      另外分子不能爲0,所以要進行相應的異常處理。函數

二、運算符的擴展

     實際應用中四則運算不僅僅侷限於二元運算,而是能夠有多個操做符的混合運算,顯然正常的算式順序是很難計算的,這時候就應該把算式轉化成逆波蘭式。具體操做步驟以下:性能

(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)若是該元素是運算符,出棧兩個數,計算結果再入棧,逆波蘭遍歷完後棧內的元素就是表達式的值了。函數實現以下:

三、程序流程

    目前程序設計流程爲:

(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表示「 」,主要是爲了算式美觀,將分數的/和除法的/區分開,另外考慮到之後可能要加負數,防止混淆)

2、代碼實現

    代碼使用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("\r\n");
 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

3、遇到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初始化語句放到循環外,這裏不肯節外生枝,在主程序的開頭就聲明:

4、部分程序截圖

        程序運行的部分截圖以下:(爲了美觀,格式化輸出如Console.Write("{0,-20}", ques[i] + operators[4]);表示向左對齊,佔20個字符)

5、程序可改進處

       程序的進度就是這樣,但無可避免地也會有缺陷,接下來幾周須要改進的有:

(1)目前的整數和分數都是正數,而負數沒有考慮,考慮的話會負號和減號會混淆,雖然運算符先後有空格,可若是單獨給負數加括號的話,會使算式可讀性變差。

(2)目前遇到除零的問題,只是單單說起到除號緊跟着的操做數不能爲零,可2 / (2-2)這種狀況沒有考慮,因此每次生成算式的時候,要先計算下結果,若是算式拋出異常則捨棄該算式從新生成。

(3)目前操做數和運算符的個數、範圍都是固定的幾個(隨機生成),之後可能會將其參數化,好比-r表示操做數的範圍,-n表示運算符的個數。

(4)目前沒有考慮到用戶輸入異常的問題,之後要加入異常處理提醒用戶正常輸入。

  (5) 目前生成的算式尚未檢查是否重複,雖然這種狀況發生的機率很小,但仍是要檢測/(ㄒoㄒ)/~~。初步想法是加法和乘法的運算符鄰近的兩個操做數是否知足交換律。

(6)因爲括號的位置是隨機生成的,這樣就會出現(2+2)+ 4或者(2+3)這種無心義的括號,無心義只可意會不可言傳,因此尚未想到好的解決方案。

(7)代碼優化的必要性。目前是c#語言,可否擴展成網頁程序、C語言等等?

      總結下來,問題仍是不少的~( ̄▽ ̄~)(~ ̄▽ ̄)~!

相關文章
相關標籤/搜索