天天看點

軟體工程第五次作業--四則運算

題目

   (1)能自動生成國小四則運算題目;

   (2)能支援任意分數的四則運算;

   (3)能支援任意括号運算

思路

  根據參數生成不定長度的表達式,以及能控制是否生成分數,能生成任意數量的中綴表達式,支援四則運算,括号運算以及分數運算

  構造函數接口  def __init__(self, exps_num=10, num_l=1, num_r=10, exp_limit_len=10, has_fraction=True)

  提供接口生成中綴表達式,傳回表達式資料集   def create_express(self)

  提供接口将中綴表達式化為字尾表達式  def get_postfix(self, exp)

  提供接口将字尾表達式進行計算并傳回結果  def cal_express(self, exp)

  提供接口以使用者友好方式顯示中綴表達式  def get_showExp(self, exp)

源代碼      
# -*- coding: utf-8 -*-
# author: 'boliang'
# date: 2018/4/18 21:04

import profile
import random
from fractions import Fraction

class Solution(object):
    def __init__(self, exps_num=10, num_l=1, num_r=10, exp_limit_len=10, has_fraction=True):
        self.__exps_num = exps_num
        self.__has_fraction = has_fraction
        self.__exp_limit_len = exp_limit_len
        self.__num_l = num_l
        self.__num_r = num_r

    # 生成中綴表達式
    def create_express(self):
        exps = []
        num = self.__exps_num
        while num > 0:
            num_len = random.randint(2, self.__exp_limit_len)
            tmp_len = num_len - 1
            exp = [self.__get_num(self.__has_fraction)]
            while tmp_len > 0:
                # 1為+,2為-,3為*,4為/
                op_flag = random.randint(1, 4)
                if op_flag == 1:
                    exp.append('+')
                elif op_flag == 2:
                    exp.append('-')
                elif op_flag == 3:
                    exp.append('*')
                else:
                    exp.append('/')
                exp.append(self.__get_num(self.__has_fraction))
                tmp_len -= 1

            brackets = random.randint(0, int(len(exp)/8))
            while brackets > 0:
                if self.__set_bracket(exp, num_len):
                    brackets -= 1

            exps.append(exp)
            num -= 1

        return exps


    def __set_bracket(self, exp, num_len):
        index_a = 0
        index_b = 0
        while index_a == index_b:
            rec = list(map(lambda x:random.randint(0, num_len-1), range(2)))
            index_a = min(rec) + 1
            index_b = max(rec) + 1

        cal = 0
        length = len(exp)
        for i in range(length):
            if type(exp[i]) != type('+'):
                cal += 1

            if cal == index_a:
                if i+1 <= length and exp[i+1] == ')':
                    return False
                exp.insert(i, '(')

        cal = 0

        for i in range(len(exp)):
            if type(exp[i]) != type('+'):
                cal += 1

            if cal == index_b:
                if i-1 >= 0 and exp[i-1] == '(':
                    return False
                exp.insert(i+1, ')')
                break

        return True

    # 生成一個數, 包括分數
    def __get_num(self, has_fraction=True):

       # 生成包括有分數
        if has_fraction:
            # 80%幾率為整數
            flag = random.randint(1, 10)
            if flag <= 8:
                return self.__get_num(False)
            else:
                 return Fraction(self.__get_num(False), self.__get_num(False))
        # 生成整數
        else:
            return random.randint(self.__num_l, self.__num_r)

    # 計算字尾表達式
    def cal_express(self, exp):
        record = []
        for val in exp:
            if type(val) == type('+'):
                b = record.pop(-1)
                a = record.pop(-1)
                if val == '+':
                    record.append(a+b)
                elif val == '-':
                    record.append(a-b)
                elif val == '*':
                    record.append(a*b)
                else:
                    record.append(a/b)
            else:
                record.append(val)

        return record[0]

    # 通過中綴表達式得到字尾表達式
    def get_postfix(self, exp):
        l_ops = {
            '(': 1, '*': 5, '/': 5,
            '+': 3, '-': 3, ')': 6
        }

        r_ops = {
            '(': 6, '*': 4, '/': 4,
            '+': 2, '-': 2, ')': 1
        }

        op_stack = []
        post_stack = []
        for val in exp:
            if type(val) != type('+'):
                post_stack.append(val)
            elif len(op_stack) > 0:
                while len(op_stack) > 0 and l_ops[op_stack[-1]] >= r_ops[val]:
                    if op_stack[-1] != '(' and op_stack[-1] != ')':
                        post_stack.append(op_stack.pop(-1))
                    else:
                        op_stack.pop(-1)

                op_stack.append(val)
            else:
                op_stack.append(val)

        while len(op_stack) > 0:
            if op_stack[-1] != '(' and op_stack[-1] != ')':
                post_stack.append(op_stack.pop(-1))
            else:
                op_stack.pop(-1)

        return post_stack


    def get_showExp(self, exp):
        op = {'+': '+', '-': '-', '*': '×', '/': '÷', '(':'(', ')':')'}
        jud_fun = lambda val: str(val) if type(val) != type('+') else op[val]
        return ' '.join(map(jud_fun, exp))


# 測試函數
def test():
    # 1. 測試程式自動生成10組表達式資料(包括分數和括号運算)
    # 2. 測試通過中綴表達式計算得到字尾表達式
    # 3. 根據字尾表達式計算結果(包括分數)

    # 設定接口參數
    # 表達式個數
    express_num = 10
    # 生成的數的下界
    num_l = 1
    # 生成的數的上界
    num_r = 10
    # 表達式的數字個數
    exp_limit_len = 10
    # 是否會生成分數
    has_fraction = True

    sol = Solution(express_num, num_l, num_r, exp_limit_len, has_fraction)

    # 生成中綴表達式
    exps = sol.create_express()


    for ind, exp in enumerate(exps):
        print('.......................................')
        print('第{0}條表達式:{1}'.format(ind+1, exp))
        tmp = sol.get_postfix(exp)
        print('字尾表達式為:{0}'.format(tmp))
        print('使用者界面中顯示的表達式:{0}'.format(sol.get_showExp(exp)))
        print('運算結果為:{0}'.format(sol.cal_express(tmp)))
        print('.......................................')


if __name__ == '__main__':
    profile.run('test()')

根據單元測試,測試結果如下      
軟體工程第五次作業--四則運算
軟體工程第五次作業--四則運算
軟體工程第五次作業--四則運算

效能分析, 運用Python profile庫

軟體工程第五次作業--四則運算
軟體工程第五次作業--四則運算
軟體工程第五次作業--四則運算

PSP表格

預計耗時(分鐘) 是實際耗時(分鐘)
Planning 計劃 10
Estimate 估計這個任務需要多少時間 100
Development 開發 120 240
Analysis 需求分析 5
Design Spec 生成設計文檔 3 23
Design Review 設計複審(和同僚稽核設計文檔) 2
Coding Standerd 代碼規範(為目前的開發制定合适的規範)
Design 具體設計
Coding 具體編碼 30 60
Code Review 代碼複審
Text 測試(自測,修改代碼,送出修改)
Reporting 報告 20
Text Report 測試報告
Size Measurement 計算工作量
Postmortem & Process Improvement Plan 事後總結,并提出過程改進計劃
Sum 合計 215 420