python实现科学计算器

作业班级

班级链接

作业要求

作业链接

项目源码地址

github地址

作业目标

通过GUI实现一个具有可视化界面的科学计算器

作业过程

界面以及功能展示

请添加图片描述

P2P表格

P2PPersonal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划3030
• Estimate:• 估计这个任务需要多少时间55
Development开发580480
• Analysis• 需求分析 (包括学习新技术)6030
• Design Spec• 生成设计文档1515
• Design Review• 设计复审1515
• Coding Standard:• 代码规范 (为目前的开发制定合适的规范)1010
• Design• 具体设计3030
• Coding• 具体编码100100
• Code Review:• 代码复审2520
• Test• 测试(自我测试,修改代码,提交修改)3020
Reporting报告6040
• Test Repor:• 测试报告:55
:• Size Measurement• 计算工作量1010
• Postmortem & Process Improvement Plan• 事后总结, 并提出过程改进计划1010
合计985820

解题思路描述

个人对python语言比较熟悉,所以这次作业采用python语言来进行编写科学计算器,在作业过程中主要问题如下,本次使用了第三方库PyQt5,运行前请先在终端运行

 pip install PyQt5  -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com 
 pip install sympy  -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com 

问题1

本次计算功能主要委托给python自带的eval函数来处理,但是eval函数无法处理想sin这样的三角函数或是 ^幂次运算符号,在

问题2

一次性清除显示界面内的内容很容易,但是如果只是清除用户上一步的操作,要避免在清除三角函数时只清除部分字母

问题3

在括号处理方面,要判断每一个正括号有没有对应的反括号,并且正确地处理括号匹配

核心代码展示

    def calt_final(self, the_cal):
        final_cal = ''
        flag = 0
        i = 0
        flag1 = 0
        flag2 = 0
        while True:
            if the_cal[i] not in num_and_op:
                if the_cal[i] == '^':
                    p = 0
                    k = i
                    the_new = ''
                    while True:
                        k -= 1
                        if k == -1 or the_cal[k].isdigit() == False:
                            break
                        else:
                            the_new = the_cal[k] + the_new
                    p = k + 1
                    k = i
                    the_new1 = ''
                    while True:
                        k += 1
                        if k == len(the_cal) or the_cal[k].isdigit() == False:
                            break
                        else:
                            the_new1 = the_cal[k] + the_new1
                    t = pow(float(the_new), float(the_new1))
                    t = str(t)
                    final_cal += the_cal[flag:p] + t
                    i = k - 1
                    flag = k
                for j in range(i + 3, len(the_cal)):
                    if the_cal[j] == '(' and flag2 == 0:
                        flag1 = j
                        flag2 = 1
                        stack.append('(')
                    elif the_cal[j] == '(':
                        stack.append('(')
                    elif the_cal[j] == ')':
                        stack.pop()
                        if len(stack) == 0:
                            flag2 = 0
                            the_new_cal = the_cal[flag1 + 1:j]
                            t = self.calt_final(the_new_cal)
                            if the_cal[i] != 'a':
                                if the_cal[i + 1] != 'q':  # tri and sqrt\
                                    t = math.radians(t)
                                if the_cal[i:i + 3] == tri_op[0]:
                                    t = sy.sin(t)
                                elif the_cal[i:i + 3] == tri_op[1]:
                                    t = sy.cos(t)
                                elif the_cal[i:i + 3] == tri_op[2]:
                                    t = sy.tan(t)
                                elif the_cal[i:i + 4] == tri_op[6]:
                                    print(1)
                                    t = math.sqrt(t)
                            else:
                                if the_cal[i:i + 4] == tri_op[3]:
                                    t = sy.asin(t)
                                elif the_cal[i:i + 4] == tri_op[4]:
                                    t = sy.acos(t)
                                elif the_cal[i:i + 4] == tri_op[5]:
                                    t = sy.atan(t)
                                t = math.degrees(t)
                            t = str(t)
                            final_cal += the_cal[flag:i] + t
                            i = j
                            flag = j + 1
                            break
            i += 1
            if i >= len(the_cal):
                break
        final_cal += the_cal[flag:len(the_cal)]
        return eval(final_cal)

接口设计与实现过程

1. 用户界面设计:

这次作业中,用户界面使用PyQt5库创建。首先,创建了一个主窗口,设置了窗口的标题、图标和大小,并在窗口中创建了两个文本框(QLineEdit),一个用于显示输入表达式,另一个用于显示计算结果。并且创建了数字按钮、运算符按钮以及其他功能按钮,并使用网格布局将它们排列在界面上。

2. 按钮事件处理:

每个按钮都关联了一个点击事件处理函数。例如,数字按钮、运算符按钮和清除按钮都有相应的事件处理函数。在这些函数中,通过获取按钮的文本内容来处理用户的输入,然后将输入显示在表达式文本框中。

3. 数学表达式计算:

计算器的核心功能是解析和计算数学表达式。代码中使用了一个自定义的方法calt_final来计算表达式。这个方法使用了一个栈来处理括号,并递归地计算表达式的值。在计算过程中处理了一些特殊的运算符,如三角函数和平方根。

4. 错误处理:

代码中也包含了错误处理部分,当用户输入无效的表达式或出现其他错误时,会在结果文本框中显示"错误"。

5. 用户体验和界面优化:

界面设计中考虑了用户体验,包括按钮的样式和布局。这有助于使应用看起来更吸引人,易于使用。

程序性能改进

  • 在最初,处理计算所使用的calt_final里采用的是循环嵌套的方法,时间复杂度较高,之后改成采用递归的算法,降低了时间复杂度
  • 一开始设计的时候,结果的输入和输出都显示在一个显示栏中,用户不方便对自己之前的操作进行观看,之后设计成输入和输出分开显示
  • 程序一开始使用python的math库中的函数对三角函数进行计算,但测试过程中发现精度不够,例如sin30会等于0.4999999,之后换成了sys

单元测试

单元测试

在这里插入图片描述

单元测试部分代码

class TestCalculator(unittest.TestCase):
    def test_cal(self):

        result = cal.calt_final('2+2-3*4/4')
        self.assertEqual(result, 1)


        result = cal.calt_final('(2+(3*4))/8*2^2')
        self.assertEqual(result,7)


        result = cal.calt_final( 'sin(45)+sqrt(16)+cos(40)+tan(45)')
        self.assertAlmostEqual(result , 6.473151224305525  )

        result = cal.calt_final('1+5^2')
        self.assertEqual(result, 26)


        result = cal.calt_final('sqrt(sin(45))')
        self.assertAlmostEqual(result, 0.8408964152537143)

        result = cal.calt_final( 'asin(0.5)+acos(0.5)+atan(1)')
        self.assertAlmostEqual(result, 2.356194490192345)

异常处理

        try:
            cal = self.result_display.text()

            result = self.calt_final(cal)

            self.result_display1.setText(str(result))

        except:

            self.result_display1.setText('错误')

若是遇到eval函数无法处理的式子,则抛出错误

心路历程和收获

这次作业过程中遇到了很多困难,尤其是算法的设计,在编写主要算法过程中我遇到了很多困难和bug,好在不断地优化下慢慢解决了一个个困难。
通过这次作业,我学会了P也Qt库函数地使用,对单元测试和覆盖率有了初步的认知,对GUI程序有了更深一步的学习。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值