20242106 2024-2025-2 《Python 程序设计》实验二报告

20242106 2024-2025-2 《Python 程序设计》实验二报告

课程:《Python 程序设计》
班级: 2421
姓名: 于凯
学号: 20242106
实验教师:王志强
实验日期:2025 年 3 月 26 日
必修/选修: 公选课

一、实验内容

  • 设计并完成一个完整的应用程序,完成加减乘除模等运算,功能多多益善。
  • 考核基本语法、判定语句、循环语句、逻辑运算等知识点。

二、实验过程及结果

我写了三坨计算器。

(一)计算器一 + 算数小游戏二合一大礼包

  • 本版是最传统的老师要求的计算器,但是又不太一样,我观察到出算术题需要给出正确答案,这恰恰是计算器可以做到的,于是可以把计算的部分打包成 rvc() 函数,提高代码的复用性。
  • 计算器支持了实数和复数的加减乘除余幂三角函数对数运算,输入不合法内容会被骂 fw;算数小游戏可以生成实数和复数的加减乘除余幂对数算术题,lev 可以调节复数出现的比例,做错了也会被骂 fw。
  • 不扣 1 复活 MyGO 的小朋友要做题,而为了防止小朋友偷懒,当小朋友输入的题目数小于等于 0 时,会直接给他布置 10000 道题目。
  • 代码:
    import cmath;import math;import random
    def add(a,b):return a+b
    def sub(a,b):return a-b
    def mul(a,b):return a*b
    def div(a,b):
        if b==0:return-1
        return a/b
    def mod(a,b):
        if isinstance(a,complex)or isinstance(b,complex):return -1
        if b==0:return -1
        return a%b
    def pow(a,b): return a**b
    def log(a,b):
        if isinstance(a,complex)or isinstance(b,complex):
            if a==0 or a==1 or b==0:return -1
            return cmath.log(b,a)
        else:
            if a<=0 or a==1 or b<=0:return -1
            return math.log(b,a)
    def sin(num):return cmath.sin(num) if isinstance(num,complex) else math.sin(num)
    def cos(num):return cmath.cos(num) if isinstance(num,complex) else math.cos(num)
    def tan(num):return cmath.tan(num) if isinstance(num,complex) else math.tan(num)
    def cout(fuck,ans):
        if fuck==0:
            if isinstance(ans,int)or ans.is_integer():print('=',int(ans))
            else:print('=',f"{ans:.6f}")
        else:print('=',ans)
    def rvc(a,b,op):
        if op=='+':return add(a,b)
        elif op=='-':return sub(a,b)
        elif op=='*':return mul(a,b)
        elif op=='/':return div(a,b)
        elif op=='%':return mod(a,b)
        elif op=='**':return pow(a,b)
        elif op=='log':return log(a, b)
        else:return -1
    def cal():
        print("支持类型:整数、浮点数、复数(j表示虚部)");print("支持运算:加-+,减-,乘*,除/,余%,幂**,三角函数(sin/cos/tan),对数(a log b)")
        while True:
            parts=input("\n输入表达式(空格分隔):").split()
            if not parts:continue
            if len(parts)==2:
                op,num_str=parts
                if op not in ('sin','cos','tan'):print("fw");continue
                if 'j' in num_str:num=complex(num_str);fuck=1
                else:num=float(num_str);fuck=0
                if op=='sin':ans=sin(num)
                elif op=='cos':ans=cos(num)
                elif op=='tan':ans=tan(num)
                else:continue
                if isinstance(ans,(complex,float)):cout(fuck,ans)
                else:print("fw")
            elif len(parts)==3:
                a_str,op,b_str=parts
                if 'j' in a_str or 'j' in b_str:a=complex(a_str);b=complex(b_str);fuck=1
                else:a=float(a_str);b=float(b_str);fuck=0
                ans=rvc(a,b,op)
                if ans!=-1:cout(fuck,ans)
                else:print("fw")
            else:print("fw")
            if input("按任意键继续/0退出:")=='0':print('拜拜喽您内');break
    def rec():
        ops=['+','-','*','/','**','log'];op=random.choice(ops);lev=random.random()<0.3
        if lev:
            a=complex(random.randint(-5,5),random.randint(-5,5));b=complex(random.randint(-5,5),random.randint(-5,5))
            while op=='/' and b==0j:b=complex(random.randint(-5,5),random.randint(-5,5))
            while op=='log' and (a==0 or b==0):a=complex(random.randint(-5,5),random.randint(-5,5));b=complex(random.randint(-5,5),random.randint(-5,5))
        else:
            a=random.randint(-10,10);b=random.randint(-10,10)
            while op=='/' and b==0:b=random.randint(-10,10)
            while op=='log' and (a<=0 or a==1 or b<=0):a=random.randint(2,10);b=random.randint(2,10)
        print("题目:"+str(a)+op+str(b)+"=?");user_ans=input("输入答案(格式:a+bj):")
        if op=='log':correct=log(a,b)
        else:correct=rvc(a,b,op)
        if isinstance(correct,complex):
            try:
                user=complex(user_ans)
                if abs(user-correct)<0.001:print("正确")
                else:print("fw,正确答案是"+str(correct))
            except:print("fw")
        else:
            try:
                user=float(user_ans)
                if abs(user-correct)<0.001:print("正确")
                else:print("fw,正确答案是"+correct)
            except:print("fw")
    def rand():
        fuck=int(input('孩子你想要多少题'))-int('0')
        if fuck<=0:print('懒蛋,该罚');fuck=10000
        while fuck>0:fuck-=1;rec()
    print('扣 1 复活 MyGO');MyGO=input()
    if MyGO=='1':cal()
    else:rand()
    
  • 运行结果 1:
  • 运行结果 2:
  • 运行结果 3:
  • 运行结果 4:

(二)计算器二

  • 本版利用栈模拟了后缀表达式的计算,参考资料放在最后了,代码的核心就是将读入的中缀表达式转换为后缀表达式,再利用栈计算。好处是不用像上面的那版忘打空格会被骂 fw 了,坏处是支持的运算更少了。
  • 代码:
    def tokenize(expression):
        tokens=[];i=0
        while i<len(expression):
            c=expression[i]
            if c.isspace():i+=1;continue
            if c=='-':
                if i==0 or expression[i-1] in {'+','-','*','/','%','^','('}:
                    i_start=i;num=[c];i+=1
                    while i<len(expression) and (expression[i].isdigit() or expression[i]=='.'):num.append(expression[i]);i+=1
                    if i==(i_start+1):tokens.append('-')
                    else:tokens.append(''.join(num))
                else:tokens.append(c);i+=1
            elif c in '.0123456789':
                num=[]
                while i<len(expression) and (expression[i].isdigit() or expression[i]=='.'):num.append(expression[i]);i+=1
                tokens.append(''.join(num))
            else:tokens.append(c);i+=1
        return tokens
    def infix_to_postfix(tokens):
        op_priority={'+':1,'-':1,'*':2,'/':2,'%':2,'^':3,'(':0};stack=[];output=[]
        for token in tokens:
            if token=='(':stack.append(token)
            elif token==')':
                while stack and stack[-1]!='(':output.append(stack.pop())
                if not stack:raise ValueError("fw")
                stack.pop()
            elif token in op_priority:
                while stack and stack[-1]!='('and op_priority[token]<=op_priority[stack[-1]]:output.append(stack.pop())
                stack.append(token)
            else:output.append(token)
        while stack:
            if stack[-1]=='(':raise ValueError("fw")
            output.append(stack.pop())
        return output
    def cal(postfix):
        stack=[]
        for token in postfix:
            if token in '+-*/%^':
                if len(stack)<2:raise ValueError("fw")
                b=stack.pop();a=stack.pop()
                if token=='+':stack.append(a+b)
                elif token=='-':stack.append(a-b)
                elif token=='*':stack.append(a*b)
                elif token=='/':
                    if b==0:raise ValueError("fw")
                    stack.append(a/b)
                elif token=='%':
                    if b==0:raise ValueError("fw")
                    stack.append(a%b)
                elif token=='^':stack.append(a**b)
            else:
                try:val=float(token)
                except ValueError:raise ValueError("fw")
                stack.append(val)
        if len(stack)!=1:raise ValueError("fw")
        return stack[0]
    expression=input("请输入一个中缀表达式(例如:3+5*2),支持+、-、*、/、%、^、(、):")
    try:print("="+str(cal(infix_to_postfix(tokenize(expression)))))
    except ValueError as e:print("错误,",e)
    
  • 运行结果:

(三)计算器三

  • 最短的一版,python 自带的 eval 函数可以直接执行传入的语句,而 python 的计算语句就是最短的、易懂的中缀表达式。
  • 代码:
    print(eval(input("请输入表达式")))
    
  • 运行结果:

(四)折腾了一下博客园的主题

  • 细节后面再搞,这下干净多了。

三、实验过程中遇到的问题和解决过程

  • 问题 1:三个计算器各有各的优点,有没有办法做到兼而有之。
  • 问题 1 解决方案:其实非常麻烦,去查了一下,好像真没有人闲着没事做这东西,都是做个简易版的练手就完事了。

四、其他(感悟、思考等)

  • 半夜干活效率高。
  • JetBrains Mono 字体太好看了我草。

五、参考资料

posted @ 2025-04-06 06:35  thedyingkai_(TDK)  阅读(53)  评论(0)    收藏  举报