• 四则运算


    Github项目地址:

    https://github.com/SwallowQAQ/caculate

    psp 表格

     

    解题思路:

        首先明确四则运算是先乘除后加减,如果有括号,先计算括号内的,再计算括号外的。一道四则运算的算式不一定有四种符号,一般指由两个或两个以上运算符号及括号,把多数合并成一个数的运算。

        所以要考虑的问题有:是否要生成括号,生成几个运算符,计算数值的范围,计算结果不能为负数,除数不能为0。

        这道题中,为了便于测试,我设定数值范围是0到20的数字,如果需要可以修改,考虑题目里可能会出现分数的情况,可以设定计算几道题和可以设定运算符数量,时间问题,这次的题目中未考虑括号。

    函数设计:

        函数主要分成三个,主函数main(),随机生成表达式expression(n),计算表达式js(s)。

        获取用户需要的设定通过主函数完成,包括循环生成表达式和计算得分,生成表达式是通过列表保留每个数字和运算符,再转换成字符串显示给用户,在将这个列表通过计算表达式的函数将列表转换成可用eval()函数直接计算的字符串。

    代码说明:

    from fractions import *
    import random
    def main():#主函数
        print('输入题目的数量:')
        n = int(input())
        print('输入运算符的数量(建议2或3):')
        fn = int(input())
        print("本次共 {} 题,满分 100 分".format(n))
        flag=0
        for i in range(n):
            while 1:
                ex = expression(fn)
                an=eval(js(ex))
                s=str(an)
                if '.' in s:
                    continue
                if an>=0:
                    if '/'in s:
                        if an >1:
                            continue
                    a=''.join(ex)
                    print(a)
                    if eval(input())==an:
                        flag+=1
                        print('回答正确!')
                    else:
                        print("回答错误!,正确答案是{}".format(an))
                    break
        print("共答对{}题,本次得分:{}".format(flag,round(100/n*flag)))
    def expression(n):#生成表达式
        f = ['+','-','*','÷','/']
        fl = []
        ex = []
        pren = 0
        pre = ''
        for i in range(n+1):
            if pre == '÷':
                pren = random.randint(1, 20)
                pre = f[random.randint(0, 2)]
            elif pre == '/':
                pren = random.randint(1, 20)
                pre = f[random.randint(0, 2)]
                ex.append(str(pren))
                ex.append(pre)
                pren = random.randint(1, 20)
                pre = f[random.randint(0, 2)]
            else:
                pren = random.randint(1, 20)
                pre = f[random.randint(0, 4)]
            ex.append(str(pren))
            ex.append(pre)
        ex[-1] = '='
        return ex
    def js(s):#返回可计算字符串
        f = ['+', '-', '*', '÷', '/']
        l=len(s)
        jg=''
        for i in range(0,int(l/2)-1):
    
            if s[2*i+1] in f[:4]:
                if i==0:
                    jg=jg+s[0]
                if s[2*i+3] =='/':
                    if s[2*i+1] =='÷':
                        jg = jg + '/'
                    else:
                        jg=jg+s[2*i+1]
                else:
                    if s[2*i+1] =='÷':
                        jg = jg + '/'+ s[2*i+2]
                    else:
                        jg = jg +s[2*i+1]+ s[2*i+2]
            else:
                jg=jg+'Fraction('+s[2*i]+','+s[2*i+2]+')'
        return str(jg)
    main()

    运行结果:

    说明:/是表示分子和分母的分割线,÷才是表示除法。

    代码测试:

        expression(n)函数主要是生成表达式,因此不能直接测试,但生成的表达式需要进行修改成可计算的表达式,因此两个函数都是不能直接测试的,但是可以测试生成的表达式经过修改是否可以直接计算,如果出现修改后的表达式为(2+3)2,这种情况用eval是会出错的,在写代码时候我是有一边测试的,一些基本的错误改过来了,现在写一个测试代码,测试1w个例子,代码如下:

    def test():
        for i in range(10000):
            ex=expression(2)
            a=js(ex)
            b=eval(a)

    运行结果:

        也就是表明表达式都是可以计算的,每道题是否合法是用主函数控制的,当结果是负数或者为假分数或者为小数的时候,重新生成表达式。

        其实这样的代码是有一些问题的,比如我测试的时候发现有3-8+8这样的例子,计算结果不为负数,但是其实算不合法的,因为按顺序计算3-8已经出现负数了,因此该加入一个新的函数,用于测试可计算的表达式是否合法,以及将表达式计算结果是否合理也放在该函数中判断,再返回合理的表达式。这时主函数也应修改,修改代码不作展示。

    性能分析:

        性能分析使用pycharm中提供的profile工具测试,如下图

        思路:在当前代码下,点击proifle这个工具的时候,是和普通的运行函数一样的,但是当程序结束会附带一个分析表,而测试结果和设定的题目数量等有关系,如果按照一般的流程,等待用户输入的时间应该是最大的,这里我将函数代码修改一下,将问题数量设为10000,运算符为2,将需要用户输入的地方修改成100。

    运行结果如下

    也就是说这10000道题中有147道题的结果为100,具体是哪些就不看了,接下来看看性能统计表,如下所示

        由表可以看出,eval和expression和js函数都调用了30160次,也就是每次生成一个表达式时候都需要做一次计算,并且可以知道大约生成3次表达式,才有一条的计算结果是符合要求的。

        看到调用次数最多的是生成随机数的函数,这个和运算符数量还有式子个数有关,最少要生成((2*运算符数量+1)*式子数量),但这里直接跟调用expression函数有关。

        js这个函数花的时间是较少的,但eval和expression两个函数都花比较多的时间,eval是不可避免的,每一个式子都必须要计算一次,才能得出结果,因此可以考虑修改一下expression函数,让他的返回结果是合法的。降低调用expression函数的次数,eval的次数也减少,总时间就会减少了。

    个人总结

    知识总结:

    1. Fraction()-->完成分数的表示和计算,并且用分数表示出来。
    2. eval()-->可以自动进行四则混合运算(带括号),但是本次题目没有加入括号运算
    3. 代码测试-->可以发现程序隐藏的错误。
    4. 性能测试-->能够很方便地看到程序的运行时间及效率,对于以后的修改可以更加专业且有针对性。

    个人感悟:

        题目看起来很简单,但是分析起来会发现有特别多的情况,如果只是随机生成数字运算会比较简单,结果有要求又会变得麻烦一些,加上括号可能更复杂,个人练习比较少,写个不是很复杂的代码也花很长时间,又加上对各种函数不熟悉,做起来更慢,需要多练习才行。以后有机会再将这个四则运算功能写更完善一些。

  • 相关阅读:
    XP的定时关机命令?
    Vim简明教程【CoolShell】
    我和小美的撸码日记(3)之中的一个句话搞定MVC表单页数据绑定与提交
    Linux/RedHat 编译安装GNU gcc 4.9.0 (g++)
    真实股市房市信托本质,金融故事三则:钱都去哪儿了?
    一分钟制作U盘版BT3
    Android Studio中导入第三方库
    WebService究竟是什么?
    “权限”用英语该用哪个?
    Cocos2d-x v3.0 新的事件调度方法 lambda表达式的使用
  • 原文地址:https://www.cnblogs.com/Swalllow/p/8878971.html
Copyright © 2020-2023  润新知