因爲四則運算要支持分數,剛開始我想着是自定義分數這種數據類型,然後再重載運算符。可當整數和分數混合運算的話,就要考慮到數據類型間的轉化,比較麻煩。因而我轉化了下思路,即將整數當作是特殊的分數(分母爲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表示「 」,主要是爲了算式美觀,將分數的/和除法的/區分開,另外考慮到之後可能要加負數,防止混淆)
代碼使用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 }
(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 }
在代碼編寫的過程當中,遇到層出不窮的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語言等等?
總結下來,問題仍是不少的~( ̄▽ ̄~)(~ ̄▽ ̄)~!