此作业的要求:[https://edu.cnblogs.com/campus/nenu/2018fall/homework/2148]
git地址为:[https://coding.net/u/xumonv/p/f4/git/tree/master/f4]
一、要求1
1.给出每个功能的重点、难点、编程收获。
功能一:
重点:支持出题4个数的四则运算题目,程序中要有4个操作数和3个运算符,所有题目要求作者有能力给出正确答案。
难点:
(1)对于结果的处理,题目要求(1/3 != 0.33333333333333333333333333333333,而是无限长),也就是说对于结果为除不尽的小数时,要以分数的形式输出到控制台。此时运用Python中自带的Fraction(a,b)函数与上网查找的求质因子函数可以达到这一效果。如果质因子里面有3或者7(但是在写功能四进行测试的时候,我们发现分母有可能趋向于很大的数,这时这种求质因子的方法有时候就不适用),那么就说明算出的结果除不尽,就用分数表示。反之,则用小数表示。
(2)在运算过程中,因为要符合数学的运算逻辑与方式,所以除号 ‘/’ 后面不能出现0,我们通过判断语句的方式,排除了这样出题的可能。
编程收获:
在实现功能一的过程中,学会了Fraction函数和eval函数。
重要代码:
1 ##求一个数的所有质因子 2 def zyz(fenmu): 3 s = [] 4 while fenmu not in [1]:# 循环保证递归 5 for index in xrange(2, fenmu + 1): 6 if fenmu % index == 0: 7 fenmu /= index # let n equal to it n/index 8 if fenmu == 1: # This is the point 9 s.append(index) 10 else : # index 一定是素数 11 s.append(index) 12 break 13 return s
1 a, b, c, d = Fraction(random.randint(0, 9), random.randint(1, 9)), Fraction(random.randint(0, 9), random.randint(1, 9)), 2 Fraction(random.randint(0, 9), random.randint(1, 9)), Fraction(random.randint(0, 9), random.randint(1, 9)) 3 operator = ['+', '-', '*', '/'] 4 tag1, tag2, tag3 = random.randint(0, 3), random.randint(0, 3), random.randint(0, 3) 5 operator1, operator2, operator3 = operator[tag1], operator[tag2], operator[tag3] 6 x = random.randint(0, 9) 7 list = [['(', '', '', ')', '', ''], ['', '(', '', '', ')', ''], ['', '', '(', '', '', ')'], ['(', '', '(', ')', '', ')'], 8 ['((', '', '', ')', ')', ''], ['', '(', '(', '', '', '))'], ['(', '(', '', '', '))', ''], ['', '((', '', '', ')', ')'], 9 ['(', '', '', '', ')', ''], ['', '(', '', '', '', ')']] 10 bkl1, bkl2, bkl3, bkr1, bkr2, bkr3 = list[x][0], list[x][1], list[x][2], list[x][3], list[x][4], list[x][5]
功能二:
重点:在实现功能一的基础上给试题添加括号。
难点:
(1)我们在开始的时候想通过随机数的方式给试题添加括号,由于发现这种方式很难实现,我们思考了很久,最后选择用枚举法的方式列举出所有可能的加括号的方式。
(2)在加括号之后,我们又在操作数的运算顺序上陷入了沉思,最后,我们采取逆波兰,正则表达式,中缀转后缀表达式这些重要的工具,实现了对有括号的题目进行运算并得出正确结果。
编程收获:
这一阶段学习了逆波兰,正则表达式,中缀转后缀等重要的知识。
重要代码:
1 #自定义栈 2 class PyStack(object): 3 4 def __init__(self, initSize=20, incSize=10): 5 self.initSize = incSize 6 self.incSize = incSize 7 self.stackList = [] 8 self.top=self.bottom = 0 9 10 def push(self, ele): 11 if self.top-self.bottom >= self.initSize: 12 self.incSize += self.initSize 13 self.stackList.append(ele) 14 self.top += 1 15 16 def pop(self): 17 if self.top - self.bottom > 0: 18 self.top -= 1 19 ret = self.stackList.pop() 20 return ret 21 else: 22 return None 23 24 def len(self): 25 return self.top-self.bottom 26 27 ##算式转化为中缀表达式列表 28 def equation2List(equation): 29 # equation = raw_input("请输入你要运算的方程:") 30 result = [] 31 buffNum = [] 32 for i in equation: 33 if i.isdigit(): 34 buffNum.append(i) 35 else: 36 if len(buffNum) > 0: 37 result.append("".join(buffNum)) 38 buffNum = [] 39 result.append(i) 40 if len(buffNum)>0: 41 result.append("".join(buffNum)) 42 buffNum = [] 43 # logging.info(result) 44 return result 45 46 ##中缀表达式转后缀表达式 47 ## 1+2*(3+4)=15 48 ##1 2 3 4 + * + 49 def mid2EndSuffix(list): 50 resultList = [] 51 stack = PyStack() 52 for i in list: 53 if isnumber(i): 54 resultList.append(i) 55 elif ')' == i: 56 while stack.len() > 0: 57 item = stack.pop() 58 # logging.debug(")pop==%s"%(item)) 59 if '(' == item: 60 break 61 else: 62 resultList.append(item) 63 elif '+' == i or '-' == i: 64 if stack.len() == 0: 65 stack.push(i) 66 # logging.debug("+-None=push==%s"%i) 67 else: 68 while stack.len()>0: 69 item2 = stack.pop() 70 # logging.debug("+-=pop==%s"%item2) 71 if '(' == item2: 72 stack.push(item2) 73 # logging.debug("+-=(push==%s"%item2) 74 break 75 else: 76 resultList.append(item2) 77 stack.push(i) 78 # logging.debug("+-lastpush==%s"%i) 79 elif '*' == i: 80 if stack.len() > 0: 81 item4 = stack.pop() 82 if '/' == item4: 83 resultList.append(item4) 84 else: 85 stack.push(item4) 86 stack.push(i) 87 # logging.debug("*/(push==%s" % i) 88 elif '/' == i or '(' == i: 89 stack.push(i) 90 # logging.debug("*/(push==%s" % i) 91 else: 92 print("输入格式有误") 93 while stack.len()>0: 94 item3=stack.pop() 95 # logging.debug("last==pop=%s"%item3) 96 resultList.append(item3) 97 return resultList 98 99 ##后缀表达式计算结果 100 def calEndSuffixResult(list): 101 stack = PyStack() 102 sumEnd = 0 103 if len(list) == 0: 104 return sumEnd 105 for i in list: 106 if isnumber(i): 107 stack.push(Fraction(i)) 108 elif '+' == i: 109 a = stack.pop() 110 b = stack.pop() 111 stack.push(b + a) 112 elif '-' == i: 113 a = stack.pop() 114 b = stack.pop() 115 stack.push(b - a) 116 elif '*' == i: 117 a = stack.pop() 118 b = stack.pop() 119 stack.push(b * a) 120 elif '/' == i: 121 a = stack.pop() 122 b = stack.pop() 123 f = Fraction(b, a) 124 if a == 0: 125 print '%d/%d分子不能为0' % (b,a) 126 else: 127 stack.push(f) 128 return stack.pop()
功能三:
重点:限定题目数量,"精美"打印输出,避免重复。(这里我们没有实现让可以通过交换律、结合律等方式相互转换的题目不重复出现)
难点:除了不重复出题的功能,还有通过命令行输入指定要打印的题目数量,同时,为了方便老师打印,需要将结果统一打印在题目右面空白区域的一侧(以每个结果最左端的数字对齐)。还有要使用重定向的功能将程序出的题目打印到.txt 文档中,这个不难办到。
编程收获:
这一阶段有用到重定向的功能,由于上一次作业时没有理解重定向,所以对重定向进行了复习。
功能四:
重点:支持分数出题。
难点:
(1)这里需要将每个操作数转换成和之前三个功能都不一样的分数,而转换成分数后,我们发现运算顺序又会因为操作数里面的除号‘/’而改变,所以我们将每个操作数两边都加了括号避免发生运算顺序的错误。
(2)功能四要求结果用带分数表示,正则表达式可以解决这一问题。
编程收获:
在编程的过程中,越来越发现正则表达式是个很重要的工具。
重要代码:
1 if '/' in str(truth): 2 lstre = re.match(r'^(-?)(d+)/(d+)$', str(truth)).groups() 3 fuhao = lstre[0] 4 fenzi = int(lstre[1]) 5 fenmu = int(lstre[2]) 6 # fenzi = int(str(truth).split('/')[0]) 7 # fenmu = int(str(truth).split('/')[1]) 8 if fenzi > fenmu: 9 pre = fenzi // fenmu 10 aft = fenzi % fenmu 11 truth = fuhao + str(pre) + ' ' + str(aft) + '/' + str(fenmu) 12 truth = str(truth)
1 bkl1, a, operator1, bkl2, b, bkr1, operator2, bkl3, c, bkr2, operator3, d, bkr3 = init() 2 eList = equation2List(bkl1 + '(' + str(a) + ')' + operator1 + bkl2 + '(' + str(b) + ')' 3 + bkr1 + operator2 + bkl3 + '(' + str(c) + ')' + bkr2 + operator3 + '(' + str(d) + ')' + bkr3)
2.结对编程的体会
通过这些天与徐常实同学的结对编程,我觉得结对编程是个有趣而且很有意义的编程方式,比如,我在敲代码时出现了自己没发现的问题,队友可以及时纠正我,或者思路出现断点,队友确实可以像“领航员”一样指引出一个方向。不过,在做“领航员”的时候,也感受到了这个身份的不易,如果有一个时间段徐常实想不到解决问题的方法,这时候重任就都在我的身上,在想解决方法的时候确实很伤脑筋,很不轻松。在结对的过程中,我们没有太大的摩擦,最后通过两个人的共同努力,实现了本来可能一个人不能实现或者需要更长时间实现的功能的时候,我们的心情还是很激动的。
3.编码、争论、复审等活动中花费时间较长,给我较大收获的事件。
(1)在如何区分除得尽与除不尽的分数时,我们感觉很不容易,也确实用了很长的时间,直到最后我们也没有正确实现这一功能,最后干脆用分数表示所有的结果。
(2)在计算带括号的算式时,逆波兰是个很关键的工具。学习逆波兰,中缀转后缀花费的时间很久。
(3)在测试代码的过程中,有很多报错的时候都是因为str型变量与int型变量不匹配,这也提醒了我写代码时要经常注意这个问题。
(4)给算式加括号花费的时间是最长的,最后选择列举所有括号可能出现的情况来解决问题。
(5)出现除0的算式需要排除,重新出题。耗费了很长时间后,我们终于使用try与except函数解决了这一问题。
4.点评我的伙伴——徐常实同学
优点:徐常实同学虽然是一名跨考生,但是解决问题的想法层出不穷,并且对实现自己的想法兴趣十足。尤其是在我想法枯竭的时候,能很快的想出一个我们都认为可行的方法。
缺点:由于缺少过硬的专业能力,在践行自己的想法时很容易遇到困难。
二、要求二:给出照片1张,包括结对的2位同学、工作地点、计算机,可选项包括其他能表达结对编程工作经历的物品或场景。
工作地点:冬华公寓 B523
使用我(张帅)的电脑进行编程
照片:
三、要求三:使用coding.net做版本控制。