利用Python实现数据可视化(四):实现计算微积分、概率分布及可视化的GUI程序
本文介绍了一个基于Python开发的微积分计算与可视化GUI程序。该程序实现了标量函数和矢量函数的微积分计算功能,包括不定积分、定积分、二重/三重积分、方向导数、梯度、散度、旋度等高等数学概念,并提供了第一类和第二类曲线/曲面积分的计算功能。文章详细展示了各功能模块的核心代码实现,如积分计算、偏导数求解等数学运算的Python实现方式。程序采用SymPy库进行符号运算,支持用户输入数学表达式并获取
引言
本篇文章致力于通过Python语言来实现基础的微积分的计算(包含标量函数微积分和矢量函数微积分)、常见的概率分布计算和可视化的GUI运行程序。
在本人所著的“利用Python实现数据可视化(一)”和“利用Python实现数据可视化(二)”这两篇文章中,已经介绍了关于常见空间几何体的绘制和计算一维离散型、连续型随机变量的分布及其数据可视化的原理,并展现了相关的代码,由于本篇所介绍的GUI程序包含上述功能,所以在本篇文章中,我将不再介绍和展示实现上述功能的原理和代码,重点将被放在前述文章所未涉及到的内容并展示部分代码。
特别声明:如有需要GUI运行程序或者包含完整Python源代码的朋友,请移步至作者本人主页,在“资源”一栏中下载相关的文件包。
GUI程序界面



-----------------------------------------------------------分界线-------------------------------------------------------------
微积分的计算
一.基础简介
(一)导数与积分
导数(Derivative),又名微商,是微积分中的重要基础概念。导数反映的是函数的局部性质,一个函数在其定义域上某一点的导数描述了这个函数在这一点附近的变化率。导数的本质是通过极限的概念对函数进行局部的线性逼近,符号记为或
对一个函数求导和求积分是一对互逆运算,如果我们假设一个函数在其定义域上处处可导,且其导数为
,即
,那么我们就有
,其中C为任意常数。此时,可能会有人有疑问,为什么求不定积分会出现一个任意常数呢?我们可以这样想,因为导数反映的是一个函数的变化率,那么对于一个常数来说呢,例如
,无论
怎样变化、取什么值,其因变量的取值恒为5,也就是说,对于这样一个函数来说,它在任何一点处的变化率也为0,也就是导数为0。有了这个概念之后,我们可以这样理解,函数
的导数是
,那么如果对函数
作上下平移之后再对其求导呢?我们先来讨论上下平移,这和自变量
无关,只与
后面所添加或减去的那个常数有关,由于常数的导数始终为0,那么我们便可以得出,求导之后的
具体是一个什么样的表达式只与
是一个什么样的表达式有关,与求导之前的
的上下平移量无关,所以,就会得到
。
其实,如果把之前的求导方程写为,就可以更好地理解上述内容了。
如果一个函数的变量超过一个,那么我们称这个函数为多元函数,对其求导和求积分就需要用到多元函数微积分的知识了。
(二)微分方程
微分方程,是指含有未知函数及其导数的关系式。解微分方程就是找出未知函数。微分方程是伴随着微积分学一起发展起来的。微分方程的应用十分广泛,可以解决许多与导数有关的问题。物理中许多涉及变力的运动学、动力学问题,如空气的阻力为速度函数的落体运动等问题,很多可以用微分方程求解。此外,微分方程在化学、工程学、经济学和人口统计等领域都有应用。
未知函数是一元函数的,叫做常微分方程;未知函数是多元函数的,叫做偏微分方程。
例如和
二.拓展知识
(一)方向导数与梯度
想象一下,你要去爬山,我们假设这个大山可以在一个很大很大的三维空间直角坐标系中用一个函数表示出来(称其为“大山函数”),方向导数可以告诉你大山函数沿着某一个方向变化了多少,比如说,你沿着这个方向爬山,方向导数告诉你的就是大山函数沿着你所爬山的方向的海拔变化,而梯度就是方向导数的最值,也就是说,在梯度的方向上,大山函数的方向导数的变化值是最快的,即在这个方向上,海拔高度的变化是最快的。
(二)散度
散度是描述空气从周围汇合到某一处或从某一处流散开来程度的量。水平散度是气体在单位时间内水平面积的变化率。如果面积增大,散度取正值,为水平辐散;如果面积缩小,散度取负值,为水平辐合。三维空间的散度表示任意气块在单位时间内其单位体积的变化率。气块的体积膨胀称为辐散,气块体积收缩称为辐合。
(三)旋度
旋度可以表示三维向量场对某一点附近的微元造成的旋转程度。 这个向量提供了向量场在这一点的旋转性质。旋度向量的方向表示向量场在这一点附近旋转度最大的环量的旋转轴,它和向量旋转的方向满足右手定则。旋度向量的大小则是绕着这个旋转轴旋转的环量与旋转路径围成的面元的面积之比。举例来说,假设一台滚筒洗衣机运行的时候,从前方看来,内部的水流是逆时针旋转,那么中心水流速度向量场的旋度就是朝前方向外的向量。
三.代码展示
对于有些函数来说,其积分和微分并不总是可以人为地计算出来的,或者说,人为地计算是非常非常困难的,那么此时,我们就可以利用Python来帮助我们计算。
部分核心代码如下:
(一)不定积分与定积分
def calc_indefinite_integral(self):
"""计算不定积分 ∫f(x)dx"""
self.inde_result_text.clear()
try:
# 获取输入
func_str = self.inde_func_input.text().strip()
var_str = self.inde_var_input.text().strip()
if not func_str:
raise ValueError("被积函数不能为空")
if not var_str:
raise ValueError("积分变量不能为空")
# 创建符号变量
var = sympy.Symbol(var_str)
# 解析被积函数
try:
func = sympy.sympify(func_str)
except:
raise ValueError(
f"无法解析函数: {func_str}\n请使用正确的Python表达式,例如x**2表示x²,sin(x)表示正弦函数")
# 计算不定积分
integral = sympy.integrate(func, var)
# 显示结果
result = f"不定积分:∫ {func} d{var_str} = {integral} + C"
self.inde_result_text.setText(result)
except ValueError as e:
self.inde_result_text.setText(f"输入错误:{str(e)}")
except Exception as e:
self.inde_result_text.setText(f"计算错误:{str(e)}")
def calc_definite_integral(self):
"""计算定积分 ∫f(x)dx,积分区间为(a,b)"""
self.def_result_text.clear()
try:
# 获取输入
func_str = self.def_func_input.text().strip()
var_str = self.def_var_input.text().strip()
a_str = self.def_low_input.text().strip()
b_str = self.def_high_input.text().strip()
if not func_str:
raise ValueError("被积函数不能为空")
if not var_str:
raise ValueError("积分变量不能为空")
if not a_str or not b_str:
raise ValueError("积分上下限不能为空")
# 创建符号变量
var = sympy.Symbol(var_str)
# 解析被积函数
try:
func = sympy.sympify(func_str)
except:
raise ValueError(f"无法解析函数: {func_str}\n请使用正确的Python表达式")
# 解析积分上下限
try:
a = sympy.sympify(a_str)
b = sympy.sympify(b_str)
except:
raise ValueError(f"无法解析积分限: {a_str}, {b_str}")
# 计算定积分
integral = sympy.integrate(func, (var, a, b))
numeric_value = float(integral.evalf()) # 获取数值结果
# 显示结果
result = f"定积分:∫ {func_str} d{var_str}\n"
result += f"积分下限:{a}\n积分上限:{b}\n"
result += f"数值结果:{numeric_value}"
self.def_result_text.setText(result)
except ValueError as e:
self.def_result_text.setText(f"输入错误:{str(e)}")
except Exception as e:
self.def_result_text.setText(f"计算错误:{str(e)}")
(二)二重积分
def calc_double_integral(self):
"""计算二重积分 ∫∫f(x,y)dxdy"""
self.double_result_text.clear()
try:
# 获取输入
func_str = self.double_func_input.text().strip()
var1_str = self.double_var1_input.text().strip()
var2_str = self.double_var2_input.text().strip()
a_str = self.double_var1_low.text().strip()
b_str = self.double_var1_high.text().strip()
c_str = self.double_var2_low.text().strip()
d_str = self.double_var2_high.text().strip()
if not func_str:
raise ValueError("被积函数不能为空")
if not var1_str or not var2_str:
raise ValueError("积分变量不能为空")
if not a_str or not b_str or not c_str or not d_str:
raise ValueError("积分上下限不能为空")
# 创建符号变量
var1 = sympy.Symbol(var1_str)
var2 = sympy.Symbol(var2_str)
# 解析被积函数
try:
func = sympy.sympify(func_str)
except:
raise ValueError(f"无法解析函数: {func_str}\n请使用正确的Python表达式")
# 解析积分上下限
try:
a = sympy.sympify(a_str)
b = sympy.sympify(b_str)
c = sympy.sympify(c_str)
d = sympy.sympify(d_str)
except:
raise ValueError(f"无法解析积分限")
# 计算二重积分
integral = sympy.integrate(func, (var2, c, d), (var1, a, b))
numeric_value = float(integral.evalf()) # 获取数值结果
# 显示结果
result = f"二重积分:∫∫ {func_str} d{var1_str}d{var2_str}\n"
result += f"数值结果:{numeric_value}"
self.double_result_text.setText(result)
except ValueError as e:
self.double_result_text.setText(f"输入错误:{str(e)}")
except Exception as e:
self.double_result_text.setText(f"计算错误:{str(e)}")
(三)三重积分
def calc_triple_integral(self):
"""计算三重积分 ∫∫∫f(x,y,z)dxdydz"""
self.triple_result_text.clear()
try:
# 获取输入
func_str = self.triple_func_input.text().strip()
var1_str = self.triple_var1_input.text().strip()
var2_str = self.triple_var2_input.text().strip()
var3_str = self.triple_var3_input.text().strip()
a_str = self.triple_var1_low.text().strip()
b_str = self.triple_var1_high.text().strip()
c_str = self.triple_var2_low.text().strip()
d_str = self.triple_var2_high.text().strip()
e_str = self.triple_var3_low.text().strip()
f_str = self.triple_var3_high.text().strip()
if not func_str:
raise ValueError("被积函数不能为空")
if not var1_str or not var2_str or not var3_str:
raise ValueError("积分变量不能为空")
if not a_str or not b_str or not c_str or not d_str or not e_str or not f_str:
raise ValueError("积分上下限不能为空")
# 创建符号变量
var1 = sympy.Symbol(var1_str)
var2 = sympy.Symbol(var2_str)
var3 = sympy.Symbol(var3_str)
# 解析被积函数
try:
func = sympy.sympify(func_str)
except:
raise ValueError(f"无法解析函数: {func_str}\n请使用正确的Python表达式")
# 解析积分上下限
try:
a = sympy.sympify(a_str)
b = sympy.sympify(b_str)
c = sympy.sympify(c_str)
d = sympy.sympify(d_str)
e = sympy.sympify(e_str)
f = sympy.sympify(f_str)
except:
raise ValueError(f"无法解析积分限")
# 计算三重积分
integral = sympy.integrate(func, (var3, e, f), (var2, c, d), (var1, a, b))
numeric_value = float(integral.evalf()) # 获取数值结果
# 显示结果
result = f"三重积分:∫∫∫ {func_str} d{var1_str}d{var2_str}d{var3_str}\n"
result += f"数值结果:{numeric_value}"
self.triple_result_text.setText(result)
except ValueError as e:
self.triple_result_text.setText(f"输入错误:{str(e)}")
except Exception as e:
self.triple_result_text.setText(f"计算错误:{str(e)}")
(四)第一类曲线积分和曲面积分(对弧长的曲线积分和对面积的曲面积分)
在物理上,也称之为标量函数的线积分和面积分,该类积分反映的是标量函数对于其包含物体的积分,例如求解非均匀密度的物体的质量。
和
和
def calc_line_integral1(self):
"""计算第一类曲线积分 ∫ f(x,y,z)ds"""
self.line1_result_text.clear()
try:
# 获取输入
func_str = self.line1_func_input.text().strip()
x_str = self.line1_x_input.text().strip()
y_str = self.line1_y_input.text().strip()
z_str = self.line1_z_input.text().strip()
t_low_str = self.line1_t_low.text().strip()
t_high_str = self.line1_t_high.text().strip()
if not func_str:
raise ValueError("被积函数不能为空")
if not x_str or not y_str:
raise ValueError("曲线参数方程x(t)和y(t)不能为空")
if not t_low_str or not t_high_str:
raise ValueError("参数t的上下限不能为空")
# 创建符号变量
t = sympy.Symbol('t')
x = sympy.Symbol('x')
y = sympy.Symbol('y')
z = sympy.Symbol('z')
# 解析参数方程
try:
x_t = sympy.sympify(x_str)
y_t = sympy.sympify(y_str)
z_t = sympy.sympify(z_str) if z_str else 0
except:
raise ValueError(f"无法解析参数方程")
# 解析被积函数
try:
func = sympy.sympify(func_str)
except:
raise ValueError(f"无法解析函数: {func_str}\n请使用正确的Python表达式")
# 解析参数范围
try:
t_low = sympy.sympify(t_low_str)
t_high = sympy.sympify(t_high_str)
except:
raise ValueError(f"无法解析参数t的范围")
# 计算弧长元素ds = sqrt((dx/dt)^2 + (dy/dt)^2 + (dz/dt)^2)dt
dxdt = sympy.diff(x_t, t)
dydt = sympy.diff(y_t, t)
dzdt = sympy.diff(z_t, t)
ds = sympy.sqrt(dxdt ** 2 + dydt ** 2 + dzdt ** 2)
# 将函数中的x,y,z替换为参数方程
func_param = func.subs({x: x_t, y: y_t, z: z_t})
# 计算积分
integrand = func_param * ds
integral = sympy.integrate(integrand, (t, t_low, t_high))
numeric_value = float(integral.evalf()) # 获取数值结果
# 显示结果
result = f"对弧长的曲线积分:∫ {func_str} ds\n"
result += f"曲线参数方程:x={x_str}\n\ty={(y_str)}\n\tz={z_str}\n\n"
result += f"参数范围:t∈[{t_low}到{t_high}]\n"
result += f"数值结果:{numeric_value}"
self.line1_result_text.setText(result)
except ValueError as e:
self.line1_result_text.setText(f"输入错误:{str(e)}")
except Exception as e:
self.line1_result_text.setText(f"计算错误:{str(e)}")
def calc_surface_integral1(self):
"""计算第一类曲面积分 ∫∫ f(x,y,z)dS"""
self.surf1_result_text.clear()
try:
# 获取输入
func_str = self.surf1_func_input.text().strip()
x_str = self.surf1_x_input.text().strip()
y_str = self.surf1_y_input.text().strip()
z_str = self.surf1_z_input.text().strip()
u_low_str = self.surf1_u_low.text().strip()
u_high_str = self.surf1_u_high.text().strip()
v_low_str = self.surf1_v_low.text().strip()
v_high_str = self.surf1_v_high.text().strip()
if not func_str:
raise ValueError("被积函数不能为空")
if not x_str or not y_str or not z_str:
raise ValueError("曲面参数方程不能为空")
if not u_low_str or not u_high_str or not v_low_str or not v_high_str:
raise ValueError("参数范围不能为空")
# 创建符号变量
u = sympy.Symbol('u')
v = sympy.Symbol('v')
x = sympy.Symbol('x')
y = sympy.Symbol('y')
z = sympy.Symbol('z')
# 解析参数方程
try:
x_uv = sympy.sympify(x_str)
y_uv = sympy.sympify(y_str)
z_uv = sympy.sympify(z_str)
except:
raise ValueError(f"无法解析参数方程")
# 解析被积函数
try:
func = sympy.sympify(func_str)
except:
raise ValueError(f"无法解析函数: {func_str}")
# 解析参数范围
try:
u_low = sympy.sympify(u_low_str)
u_high = sympy.sympify(u_high_str)
v_low = sympy.sympify(v_low_str)
v_high = sympy.sympify(v_high_str)
except:
raise ValueError(f"无法解析参数范围")
# 计算偏导数
x_u = sympy.diff(x_uv, u)
x_v = sympy.diff(x_uv, v)
y_u = sympy.diff(y_uv, u)
y_v = sympy.diff(y_uv, v)
z_u = sympy.diff(z_uv, u)
z_v = sympy.diff(z_uv, v)
# 计算法向量模长 |r_u × r_v|
# i分量
i_comp = y_u * z_v - y_v * z_u
# j分量
j_comp = x_v * z_u - x_u * z_v
# k分量
k_comp = x_u * y_v - x_v * y_u
# 模长
dS = sympy.sqrt(i_comp ** 2 + j_comp ** 2 + k_comp ** 2)
# 替换变量
func_param = func.subs({x: x_uv, y: y_uv, z: z_uv})
# 被积函数
integrand = func_param * dS
# 计算积分
integral = sympy.integrate(integrand, (v, v_low, v_high), (u, u_low, u_high))
numeric_value = float(integral.evalf()) # 获取数值结果
# 显示结果
result = f"对面积的曲面积分:∫∫ {func_str } dS\n"
result += f"曲面参数方程:x={x_str}\n\ty={y_str}\n\tz={z_str}\n"
result += f"参数范围:u∈[{u_low},{u_high}]\tv∈[{v_low},{v_high}]\n"
result += f"数值结果:{numeric_value}"
self.surf1_result_text.setText(result)
except ValueError as e:
self.surf1_result_text.setText(f"输入错误:{str(e)}")
except Exception as e:
self.surf1_result_text.setText(f"计算错误:{str(e)}")
(五)第二类曲线积分和曲面积分(对坐标的曲线积分和曲面积分)
第二类曲线积分和曲面积分,在物理上,也称之为矢量函数的线积分和面积分,该类积分反映的矢量函数与积分区域之间的关系,常见的有变力做功问题和磁通量问题
和
和
def calc_line_integral2(self):
"""计算第二类曲线积分 ∫ Pdx + Qdy + Rdz"""
self.line2_result_text.clear()
try:
# 获取输入
P_str = self.line2_P_input.text().strip()
Q_str = self.line2_Q_input.text().strip()
R_str = self.line2_R_input.text().strip()
x_str = self.line2_x_input.text().strip()
y_str = self.line2_y_input.text().strip()
z_str = self.line2_z_input.text().strip()
t_low_str = self.line2_t_low.text().strip()
t_high_str = self.line2_t_high.text().strip()
if not P_str or not Q_str:
raise ValueError("矢量函数P和Q不能为空")
if not x_str or not y_str:
raise ValueError("曲线参数方程x(t)和y(t)不能为空")
if not t_low_str or not t_high_str:
raise ValueError("参数t的范围不能为空")
# 创建符号变量
t = sympy.Symbol('t')
x = sympy.Symbol('x')
y = sympy.Symbol('y')
z = sympy.Symbol('z')
# 解析参数方程
try:
x_t = sympy.sympify(x_str)
y_t = sympy.sympify(y_str)
z_t = sympy.sympify(z_str) if z_str else 0
except:
raise ValueError(f"无法解析参数方程")
# 解析向量函数
try:
P = sympy.sympify(P_str)
Q = sympy.sympify(Q_str)
R = sympy.sympify(R_str) if R_str else 0
except:
raise ValueError(f"无法解析向量函数")
# 解析参数范围
try:
t_low = sympy.sympify(t_low_str)
t_high = sympy.sympify(t_high_str)
except:
raise ValueError(f"无法解析参数t的范围")
# 计算导数
dxdt = sympy.diff(x_t, t)
dydt = sympy.diff(y_t, t)
dzdt = sympy.diff(z_t, t)
# 替换变量
P_param = P.subs({x: x_t, y: y_t, z: z_t})
Q_param = Q.subs({x: x_t, y: y_t, z: z_t})
R_param = R.subs({x: x_t, y: y_t, z: z_t})
# 计算被积函数
integrand = P_param * dxdt + Q_param * dydt + R_param * dzdt
# 计算积分
integral = sympy.integrate(integrand, (t, t_low, t_high))
numeric_value = float(integral.evalf()) # 获取数值结果
# 显示结果
result = f"对坐标的曲线积分:∫ {P_str} dx + {Q_str} dy + {R_str} dz\n"
result += f"曲线参数方程:x={x_str}\n\ty={y_str}\n\tz={z_str}\n\n"
result += f"参数范围:t∈[{t_low},{t_high}]\n"
result += f"数值结果:{numeric_value}"
self.line2_result_text.setText(result)
except ValueError as e:
self.line2_result_text.setText(f"输入错误:{str(e)}")
except Exception as e:
self.line2_result_text.setText(f"计算错误:{str(e)}")
def calc_surface_integral2(self):
"""计算第二类曲面积分 ∫∫ Pdy∧dz + Qdz∧dx + Rdx∧dy"""
self.surf2_result_text.clear()
try:
# 获取输入
P_str = self.surf2_P_input.text().strip()
Q_str = self.surf2_Q_input.text().strip()
R_str = self.surf2_R_input.text().strip()
x_str = self.surf2_x_input.text().strip()
y_str = self.surf2_y_input.text().strip()
z_str = self.surf2_z_input.text().strip()
u_low_str = self.surf2_u_low.text().strip()
u_high_str = self.surf2_u_high.text().strip()
v_low_str = self.surf2_v_low.text().strip()
v_high_str = self.surf2_v_high.text().strip()
if not P_str or not Q_str or not R_str:
raise ValueError("矢量函数P, Q, R不能为空")
if not x_str or not y_str or not z_str:
raise ValueError("曲面参数方程不能为空")
if not u_low_str or not u_high_str or not v_low_str or not v_high_str:
raise ValueError("参数范围不能为空")
# 创建符号变量
u = sympy.Symbol('u')
v = sympy.Symbol('v')
x = sympy.Symbol('x')
y = sympy.Symbol('y')
z = sympy.Symbol('z')
# 解析参数方程
try:
x_uv = sympy.sympify(x_str)
y_uv = sympy.sympify(y_str)
z_uv = sympy.sympify(z_str)
except:
raise ValueError(f"无法解析参数方程")
# 解析向量函数
try:
P = sympy.sympify(P_str)
Q = sympy.sympify(Q_str)
R = sympy.sympify(R_str)
except:
raise ValueError(f"无法解析矢量函数")
# 解析参数范围
try:
u_low = sympy.sympify(u_low_str)
u_high = sympy.sympify(u_high_str)
v_low = sympy.sympify(v_low_str)
v_high = sympy.sympify(v_high_str)
except:
raise ValueError(f"无法解析参数范围")
# 计算偏导数
x_u = sympy.diff(x_uv, u)
x_v = sympy.diff(x_uv, v)
y_u = sympy.diff(y_uv, u)
y_v = sympy.diff(y_uv, v)
z_u = sympy.diff(z_uv, u)
z_v = sympy.diff(z_uv, v)
# 计算雅可比行列式分量
# dy∧dz = (y_u z_v - y_v z_u) du∧dv
j1 = y_u * z_v - y_v * z_u
# dz∧dx = (z_u x_v - z_v x_u) du∧dv
j2 = z_u * x_v - z_v * x_u
# dx∧dy = (x_u y_v - x_v y_u) du∧dv
j3 = x_u * y_v - x_v * y_u
# 替换变量
P_param = P.subs({x: x_uv, y: y_uv, z: z_uv})
Q_param = Q.subs({x: x_uv, y: y_uv, z: z_uv})
R_param = R.subs({x: x_uv, y: y_uv, z: z_uv})
# 被积函数
integrand = P_param * j1 + Q_param * j2 + R_param * j3
# 计算积分
integral = sympy.integrate(integrand, (v, v_low, v_high), (u, u_low, u_high))
numeric_value = float(integral.evalf()) # 获取数值结果
# 显示结果
result = f"对坐标的曲面积分:∫∫ {P_str} dydz + {Q_str} dzdx + {R_str} dxdy\n"
result += f"曲面参数方程:x={x_str}\n\ty={y_str}\n\tz={z_str}\n"
result += f"参数范围:u∈[{u_low},{u_high}]\tv∈[{v_low},{v_high}]\n"
result += f"数值结果:{numeric_value}"
self.surf2_result_text.setText(result)
except ValueError as e:
self.surf2_result_text.setText(f"输入错误:{str(e)}")
except Exception as e:
self.surf2_result_text.setText(f"计算错误:{str(e)}")
(六)一元函数的导数和多元函数的偏导数
def calc_univariate_derivative(self):
"""计算一元函数的导数"""
self.uni_result_text.clear()
try:
# 获取输入
func_str = self.uni_func_input.text().strip()
var_str = self.uni_var_input.text().strip()
order_str = self.uni_order_input.text().strip()
if not func_str:
raise ValueError("函数不能为空")
if not var_str:
raise ValueError("自变量不能为空")
if not order_str:
raise ValueError("导数阶数不能为空")
# 解析导数阶数
try:
order = int(order_str)
if order <= 0:
raise ValueError("导数阶数必须是正整数")
except ValueError:
raise ValueError("导数阶数必须是正整数")
# 创建符号变量
var = sympy.Symbol(var_str)
# 解析函数
try:
func = sympy.sympify(func_str)
except:
raise ValueError(f"无法解析函数: {func_str}\n请使用正确的Python表达式")
# 计算导数
derivative = sympy.diff(func, var, order)
# 显示结果
result = f"函数f({var_str}) = {func}\n\n"
result += f"对{var_str}的{order}阶导数 = {derivative}\n\n"
self.uni_result_text.setText(result)
except ValueError as e:
self.uni_result_text.setText(f"输入错误:{str(e)}")
except Exception as e:
self.uni_result_text.setText(f"计算错误:{str(e)}")
def calc_multivariate_derivative(self):
"""计算多元函数的偏导数"""
self.multi_result_text.clear()
try:
# 获取输入
func_str = self.multi_func_input.text().strip()
vars_str = self.multi_vars_input.text().strip()
diff_var_str = self.multi_diff_var_input.text().strip()
order_str = self.multi_order_input.text().strip()
if not func_str:
raise ValueError("函数不能为空")
if not vars_str:
raise ValueError("变量列表不能为空")
if not diff_var_str:
raise ValueError("求导变量不能为空")
if not order_str:
raise ValueError("导数阶数不能为空")
# 解析变量列表
var_names = [v.strip() for v in vars_str.split(',') if v.strip()]
if not var_names:
raise ValueError("变量列表格式不正确,请使用逗号分隔")
# 检查求导变量是否在变量列表中
if diff_var_str not in var_names:
raise ValueError(f"求导变量 {diff_var_str} 不在变量列表中")
# 解析导数阶数
try:
order = int(order_str)
if order <= 0:
raise ValueError("导数阶数必须是正整数")
except ValueError:
raise ValueError("导数阶数必须是正整数")
# 创建符号变量字典
vars_dict = {v: sympy.Symbol(v) for v in var_names}
diff_var = vars_dict[diff_var_str]
# 解析函数
try:
func = sympy.sympify(func_str)
except:
raise ValueError(f"无法解析函数: {func_str}\n请使用正确的Python表达式")
# 计算偏导数
derivative = sympy.diff(func, diff_var, order)
# 显示结果
result = f"多元函数 f({','.join(var_names)}) = {func}\n\n"
result += f"对{diff_var_str}的{order}阶偏导数 = {derivative}\n\n"
self.multi_result_text.setText(result)
except ValueError as e:
self.multi_result_text.setText(f"输入错误:{str(e)}")
except Exception as e:
self.multi_result_text.setText(f"计算错误:{str(e)}")更多推荐
所有评论(0)