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
字体太好看了我草。