1. Githubのアドレスとプロジェクトメンバー
-
Sefue:https://github.com/zhengjinhuai/arithmetic-generators
-
私の小さな友人:https://github.com/jezing/arithmetic-generators
-
鄭Jinhuai 3117004637; 3117004602林曽
2. PSPテーブル:
PSP2.1 |
パーソナルソフトウェアプロセス段階 |
推定時間がかかる(分) |
実際の時間がかかる(分) |
プランニング |
計画 |
20 |
20 |
・見積り |
•このタスクが必要と推定どのくらいの時間 |
20 |
20 |
開発 |
開発 |
1560 |
1490 |
・分析 |
・分析(新しい技術を学ぶ含む)が必要 |
70 |
60 |
・デザインスペック |
設計ドキュメントの生成 |
60 |
60 |
・デザインレビュー |
・デザインレビュー(と彼の同僚は、設計文書を見直し) |
80 |
90 |
・コーディング標準 |
・コードの仕様(現在の開発のための適切な規範の開発) |
20 |
20 |
・ 設計 |
・具体的な設計 |
80 |
90 |
・コーディング |
・具体的なコーディング |
1000年 |
905 |
・コードレビュー |
・コードレビュー |
120 |
120 |
・テスト |
・テスト(セルフテスト、コードを変更し、変更を提出) |
130 |
145 |
報告 |
レポート |
150 |
150 |
・ 試験報告書 |
・テストレポート |
60 |
70 |
・サイズ測定 |
・コンピューティングのワークロード |
30 |
30 |
・死後&プロセス改善計画 |
・後知恵、およびプロセス改善計画を提案します |
60 |
50 |
トータル |
|
1730 |
1660 |
3.効果分析
入力:-rは(と題し、数万の数字と10の範囲内の分数の分母)10、-n 10000
総走行時間:最適化前3.002s
分析と最適化プロセス:
- それはプログラムが行われることが判明したパフォーマンス分析観察ランダムに生成されたオペランドと計算を
- さらにまた、見つかった冗長な計算を、分数IO書き込みスコアモジュールと時間の大きな割合つつ。
上記態様から主としてそのため、最適化プロセス。
最適化後:総走行時間1.727s
図1:最適化のパフォーマンス分析の前に
図2:最適化されたパフォーマンスの分析
追加:有効性を最適化するプロセスでは、我々は、(INGのもつれ)の議論を経て、最適化のための別の部屋を発見し、ランダムに生成するプロセスである、あなたはそれが同じ式(すなわち複雑な要件、(1を生成しません保証する休むことができます+ 2)+ 3,3 +(1 + 2)も生成されません)、そして最後の式を再確認するには、私たちの証拠のツールになります!最後に、我々は(リピートタイトルがあるかどうかをテストする)テストを書いた、1Wのトラックタイトル、トラックタイトルリピートタイトルと100W生産された場合、繰り返しスローされた例外の結果が0で試験しました。
4.設計と実装プロセス
アイデアやパネルディスカッションを設計します。
タイトルと需要分析を読んだ後、私たちはグループのプロジェクトは、式を生成し、再チェックするために、3つの部分、1に分けられます。そして最終的にはユーザー入力の回答とスコアを記録し、2番目は計算し、話題を保存して答えることです。
操作範囲を設定-rパラメータ、モジュールパラメータが-Nユーザ入力によって対象Argparseなどを発生する負のタイトル番号かどうか。
初期の議論は、我々は算術式を生成するために、単純な乱数と演算子を埋めるの使用を想定し、検出方法は、この矛盾の重みに答えを確認するために、あまり効率的で、その後の拡張を容易にしないでください。したがって、我々が議論して使用することが決定されたバイナリツリーランダムに生成された表現を。オペランドと演算子を含む層によってノードnode発現、算術バイナリツリーツリークラス発生層のクラス構造体の内部に設けられた(オペレータの親ノードをリーフノードは、図のように操作回数である。3)。加算、減算の演算処理を一致オペレータ優先op_priorityを付与し、そして結合することによって、挿入演算子は、対応する優先度を生成します。再チェック表現を生成するために後置表現を通過した後、繰り返し計算式(ます。https://www.cnblogs.com/wxrqforever/p/8679118.html再チェックアイデアはリンクを参照)かどうかを検出します。
図3:表現バイナリーツリー
その後、オペレータの優先度計算結果と併せてのfileutilsクラスの文書によると、最終的には、コンソールで答えた後、パフォーマンスのグレードを取得し、answer.txt文書をexercise.txtし、結果を保存します。
説明するために、クラス間に呼び出すのと同様の方法:
クラス説明:
-
calc_cmd.py:メインプログラムのカテゴリは、他のクラスは実行を呼び出します。
-
calc_error.py:例外クラス、全体の動作の定義にいくつかの異常、及び生成発生
-
calc_util.py:計算クラスは、式を計算するために使用され、関連する異常を返し、得点及び回答を収集します
-
expre_tree.py:生成式バイナリツリーノードに規定された方法とクラス属性と
-
FileUtils.py:ファイルタイプ、タイトルexercise.txtを格納するため、answer.txt、grade.txtファイル
-
FormatUtils.py:このような式(後置表現及び再チェック)などの炭化水素を生成し、フォーム適切な画分に分画を変換
-
unit_text.py:クラスのテスト
5.コード説明
パラメータが提出呼び出すことで、メインクラス、各クラスのメソッドの主な機能
1 parser = argparse.ArgumentParser(description="四则运算") 2 parser.add_argument('-n', dest='number', type=int, default=1, help='number of generated questions') 3 parser.add_argument('-r', dest='range', type=int, default=10, help='range of values') 4 parser.add_argument('-e', dest='exercise', type=str, help='formula expression file') 5 parser.add_argument('-a', dest='answer', type=str, help='answer expression file') 6 parser.add_argument('-g', dest='grade', type=str, help='grade file') 7 parser.add_argument('-m', dest='minus', default=False, action='store_true', 8 help='produce formulas with negative numbers') 9 args = parser.parse_args() 10 11 12 if __name__ == '__main__': 13 if args.range is None: 14 print("请输入'-r'参数控制题目中数值(自然数、真分数和真分数分母)的范围") 15 if args.exercise is None: 16 args.exercise = os.path.join(os.getcwd(), 'Exercises.txt') 17 if args.answer is None: 18 args.answer = os.path.join(os.getcwd(), 'Answer.txt') 19 if args.grade is None: 20 args.grade = os.path.join(os.getcwd(), 'Grade.txt') 21 print("欢迎进入答题模式......(输入'exit'可退出程序)") 22 t = Tree() 23 u_answer = list() # 用户答案 24 formula, s_answer = t.generate_formula(args.range, args.number, args.minus) # 随机生成表达式 25 FileUtils.write_file(formula, s_answer, args.exercise, args.answer) # 保存题目文件 26 for i in range(args.number): 27 print(formula[i], end='') 28 answer = input() # 获取用户输入的答案 29 if answer == 'exit': 30 print('退出程序成功!') 31 sys.exit() 32 u_answer.append(answer) 33 correct, wrong = CalculatorUtils.grading(u_answer, s_answer) # 统计答题结果 34 print("答题结果:") 35 print(correct) 36 print(wrong) 37 FileUtils.write_grade_file(args.grade, correct, wrong) # 保存答题结果
自定义异常类,包括不为负数、分母不超过某个值,以及运算重复的异常类对象,方便以后做扩展
class NegativeError(Exception):
"""自定义表达式不为负数的异常类"""
def __init__(self):
super(NegativeError, self).__init__() # 初始化父类
def __str__(self):
return
class DifficultError(Exception):
"""自定义分母不能超过某个值的异常类"""
def __init__(self):
super(DifficultError, self).__init__() # 初始化父类
def __str__(self): return class DuplicateError(Exception): """自定义异常类""" def __init__(self): super(DuplicateError, self).__init__() # 初始化父类 def __str__(self): return
随机生成四则运算表达式
def generate_formula(self, num_range, number, negative): """随机生成式子""" num = 0 degree = random.randrange(3, 4) # 随机设置操作数的个数 while num < number: empty_node = [self.root] for _ in range(degree): '''生成操作符号节点''' node = random.choice(empty_node) empty_node.remove(node) node.operator = random.choices(self.op_list, cum_weights=self.op_weight)[0] # node.operator = random.choices(self.op_list)[0] node.type = 2 # 每生成一个操作符号节点,生成两个空节点 node.left = Node() node.right = Node() empty_node.append(node.left) empty_node.append(node.right) for node in empty_node: '''将所有空结点变为数字结点''' node.type = 1 # 设置真分数的比重 1为整数 0为分数 num_type = random.choices(self.type_list, self.num_weight)[0] if num_type == 1: # 生成一个整数 node.number = random.randint(1, num_range) else: # 生成一个真分数 node.number = Fraction(random.randint(1, num_range), random.randint(1, num_range)) try: # self.root.show_node() # 获取生成的二叉树结构 self.root.get_answer(negative) # 计算答案 if self.root.number.denominator > 99: # 分母超过99抛出异常 raise DifficultError() self.pre_formula = self.root.get_formula() # 获取前缀表达式 self.post_formula = FormatUtils.get_result_formula(self.pre_formula) # 获取后缀表达式 self.check_formula = FormatUtils.get_check_formula(self.post_formula) # 获取查重表达式 # 进行查重 if not Tree.duplicate_check(self.check_formula, self.result_formula): # 返回false 则表明没有重复 self.result_formula.append(self.check_formula) else: raise DuplicateError output = FormatUtils.standard_output(self.pre_formula) # 格式化前缀表达式 if isinstance(self.root.number, Fraction): answer = FormatUtils.standard_format(self.root.number) # 格式化答案 else: answer = self.root.number # print(output, answer) self.formula.append(output) self.answer.append(answer) except ZeroDivisionError: # print("除数为零,删除该式子") continue except NegativeError: # print("出现负数,删除该式子") continue except DifficultError: # print("题目较难,删除该式子") continue except DuplicateError: # print("题目重复,删除该式子") continue else: num += 1 return self.formula, self.answer
计算类,可以进行操作数的运算,即生成式子之后的运算结果保存以及抛出相对应的一个异常对象
还包括了返回一个后缀表达式,和最后的评分格式。
1 class CalculatorUtils:
2
3 @staticmethod
4 def eval_formula(operator, a, b, negative=False):
5 """计算简单的加减乘除, 同时抛出不符合题目要求的异常"""
6 answer = 0
7 if operator == "+":
8 answer = a + b 9 elif operator == "-": 10 if a < b and negative is False: 11 raise NegativeError() # 抛出结果为负数的异常对象 12 else: 13 answer = a - b 14 elif operator == "*": 15 answer = a * b 16 elif operator == "/": 17 if b > 99: 18 raise DifficultError() # 抛出题目较难的异常对象(分母大于100) 19 else: 20 answer = a / b 21 # 如果答案为浮点数,则转换为分数形式 22 if isinstance(answer, float): 23 answer = Fraction(a) / Fraction(b) 24 return answer 25 26 @staticmethod 27 def get_answer(formula_list, negative): 28 """计算后缀表达式的结果""" 29 num_list = list() 30 for i in range(len(formula_list)): 31 if isinstance(formula_list[i], int) or isinstance(formula_list[i], Fraction): 32 num_list.append(formula_list[i]) 33 else: 34 b = num_list.pop() 35 a = num_list.pop() 36 res = CalculatorUtils.eval_formula(formula_list[i], a, b, negative) 37 num_list.append(res) 38 return num_list.pop() 39 40 @staticmethod 41 def grading(user_ans, ans_list): 42 """评分,同时返回要求的评分输出格式""" 43 correct = list() 44 wrong = list() 45 length = len(user_ans) 46 for i, u, ans in zip(range(1, length + 1), user_ans, ans_list): 47 if u == ans: 48 correct.append(i) 49 else: 50 wrong.append(i) 51 return correct, wrong
6. 测试运行
测试生成前缀、后缀和查重表达式:
测试生成运算式
测试答题情况及保存文件
7. 项目总结
本次结对编程收获颇多,"1 + 1 > 2"怕说的就是结对编程了。两个人一起分析题目考虑的情况比单个人的多,因此本次项目我们的算法也经得测试。分工合作,加快开发效率的同时也减少了更多的潜在错误。
本次项目采用的是命令行窗口,因此相对普通,代码方面争取在下次练习中运用更多python的特性和语法糖以提升程序性能。