最近根据PYTHON可以支持变量名可以动态的指定,结合PYTHON 的sympy符号计算库,编写了这个可以计算求解任何方程的模块函数,用法详示例,没有测试更多的方程组,随手编了两个三元二次方程组(三个未知量,三个方程,最高幂2),均得到了正确的解。
测试用主窗体的代码如下:
#文件模块名称:mathEx_Text.py
#用于测试数学计算模块mathEx.py的PYQT窗体
import os,sys #导入系统模块
import time
import math
import copy
import random
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5 import QtCore
from PyQt5.QtGui import QMovie
from PyQt5.QtCore import QByteArray
from mathEx import * #导入自定义的要测试的mathEx.py模块
##################################################################
#测试数学计算类的主窗体
class MyWidget(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('测试mathEx类:扩展数学计算库')
self.setGeometry(0, 0, 1600, 600)
self.statusbar = self.statusBar()
self.statusbar.showMessage('准备')
self.setStatusTip('准备...')
self.qimage = QImage('1.jpg') #底图
self.initUI()
def initUI(self):
self.btn_Test1=QPushButton('1测试代码1',self)
self.btn_Test1.setGeometry(1450,50,150,50)
self.btn_Test1.clicked.connect(self.test1)
self.btn_Test2=QPushButton('2测试代码',self)
self.btn_Test2.setGeometry(1450,150,150,50)
self.btn_Test2.clicked.connect(self.test2)
self.btn_Test3=QPushButton('3测试代码',self)
self.btn_Test3.setGeometry(1450,250,150,50)
self.btn_Test3.clicked.connect(self.test3)
self.Lab01=QLabel(self)
self.Lab01.setGeometry(50,50,200,200)
self.Lab01.setText('测试标签1')
#self.Lab01.raise_()
self.Lab02=QLabel(self)
self.Lab02.setGeometry(50,300,200,200)
self.Lab02.setText('测试标签2')
########################################################################################
def test1(self):
m=mathEx()
countxt='1+2*sin(sqrt(30*pi/180))'
value=m.countText(countxt)
print(f'计算公式的值{countxt}={value}')
def test2(self):
m=mathEx()
vars1='x,y,z' #此字符串中的变量名称数量及形式要出下面的方程中保持一致
lsteqs1=['x**2+y**2-z**2', #方程1:此方程中的变量名称要同vars相一致:本例用的股定律,勾3股4弦5,计划x=3,y=4,c=5看还有其也解没有
'x+y+z-12', #方程2:此方程中的变量名称要同vars相一致
'cos(atan(x/y))-4/5' #方程3:此方程中的变量名称要同vars相一致
#'方程n..........' #.方程n.......此方程中的变量名称要同vars相一致,没测试过最大支持的变更和方程数及计算用时,和是否存在BUG
]
vars2='AB,B,C' #此字符串中的变量名称数量及形式(可为多字符)要出下面的方程中保持一致
lsteqs2=['2*AB**2+3*B**2-15*AB-653', #方程1:此方程中的变量名称要同vars相一致
'5*AB**2+4*B**2-15*B-826.25', #方程2:此方程中的变量名称要同vars相一致
'2*AB + 3*B + C - 54' #方程3:此方程中的变量名称要同vars相一致
#'方程n..........' #.方程n.......此方程中的变量名称要同vars相一致,没测试过最大支持的变更和方程数及计算用时,和是否存在BUG
]
m.count_XYZ(vars1,lsteqs1) #解方程组1
m.count_XYZ(vars2,lsteqs2) #解方程组2
def test3(self):
m=mathEx()
v=m.round(m.V_cone(5),3) #保留3位小数
print(f'半径5球体积={v}')
########################################################################################
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MyWidget()
w.show()
sys.exit(app.exec())
以下为我自己编写的数学计算模块mathEx.py,没有严格作详细测试,只是供大家共同学习提高。
#mathEx.py:定义数学计算扩展库
#包括可解多元多次方程,常用的面积、体积等计算函数等,扩展中.......
import os,sys
import time
from math import *
import copy
import random
import pickle #支持保存和导入字典数据的模块(PICKLE方式:仅PTHON支持),为默认,可以保存和加载不受限制的任意数据
import json #支持保存和导入字典数据的模块(JSON方式:多种语言支持)
import csv #支持保存和导入字典数据的模块(CSV方式:多种语言支持)
import numpy as np
from scipy.optimize import fsolve
#import pandas as pd
from sympy import symbols, solve #符号计算模块
from sympy import sympify
_DEBUG_ = True #为True时,终端会输出参数帮助信息
#if _DEBUG_:print(f'\n帮助信息:调用的函数:,参数信息:参数示例:')
#定义将的所有程序#要用到各种资源文件预加载到内存中,使用时从此内存中的数据直接使用
class mathEx():
#以下定义常用数学计算常数
def __init__(self):
self.about='本类为自定义的一些常用到的数学计算公式'
#######################################################################3
def insertchar(self,original_str, char_to_insert, index):
# 在索引位置前插入字符,并返回新字符串
return original_str[:index] + char_to_insert + original_str[index:]
#以下为自定义的数学计算函数
#1、将可识别的计算公式返回计算结果
#参数:计算公式,示列:'1+2*math.sin(30*pi/180)' , 参数bAddMath=true时,将对计算文本进行处理,将math中的函数前加上前缀math.字符
def countText(self,formula,bAddMath=False):
#if _DEBUG_:print(f'\n帮助信息:调用的函数:countTxt(self,formula,bAddMath=False),参数信息:formula=计算公式字符串,bAddMath=是否为函数名前增加math.前缀参数示例:"2345+2*sin(30*PI/180)"')
try:
#先对计算公式中进行容错处理,如使用了math中的函数,如函数名前没有使用math.,应补上这几个字符串
countStr=formula
if(bAddMath): #如果要对计算字串进行二次处理
addstr='math.'
pos=0
addn=0
count=len(formula)
while pos<count-1:
c=formula[pos]
if((pos==0) or (c=='+' or c=='-' or c=='*' or c=='\\' or c=='(' )):
if(pos<count-9):
bk5str=formula[pos+1:pos+6]
bk7str=formula[pos+1:pos+8]
if(bk5str !='math.' and bk7str !='mathEx.' and formula[pos+1].isalpha()):
if(pos==0):
countStr=self.insertchar(countStr,addstr,0)
addn+=1
else:
countStr=self.insertchar(countStr,addstr,pos+1+addn*5)
addn+=1
else:
if(formula[pos+1].isalpha()):
countStr=self.insertchar(countStr,addstr,pos+1+addn*5)
addn+=1
pos+=1
print(f'计算式加工后的公式={countStr}')
value = eval(countStr)
return value
except Exception as e: # 如果发生异常,执行这里的代码
print(f'要计算的公式不正确请检查公式:{countStr}')
return None
#2、返回指小数点位数的字符串
#参数: 浮点数 指定的小数位
def round(self,fvalue,pointNum=3):
value = round(fvalue, pointNum)
return value
#3、向下取整,
def roundDown(self,fvalue):
return floor(fvalue)
#4、向上取整
def roundUp(self,fvalue):
return ceil(fvalue)
#5、度数转弧度
#参数: 十进制度数
def DegToRad(self,deg):
return deg*pi/180.0
#6、弧度转度数
#参数: 弧度数
def RadToDeg(self,rad):
return rad*180.0/pi
#7、解多元多次方程
#参数svar=''=> 要计算的变量名称,变量间用,分开
#参数lstSeqs=['方程1','方程2',........]=>方程等式列表,常规变量有几个,方程就该有几个,方程等式应将等号右侧的项全部移到左侧后再列入方程字串中
#如方程1:2*x**2+3*y+50=10*x+5,则列入方程1的字串为:2*x**2+3*y+50-(10*x+5)
def count_XYZ(self,svar,lstSeqs):
timestart=time.time()
lstVars=svar.split(',')
lstVarName=[]
lstStrName=[]
index=0
for varName in lstVars : #将方程变量字符串(建议用单字符如X Y z等)转换成代码可识别的变量名
lstVarName.append(varName)
lstStrName.append(varName)
globals()[lstVarName[index]]=varName #注,此代码后lstVarName[index]变量就是变量名了,不是值了,要用值,用列表变量lstStrName
index+=1
# 动态定义变量:加了注释的已被下面的动态语名替换,供参考原理
#x, y, z = symbols('x y z')
index = 0
count=len(lstVarName)
while index < count:
lstVarName[index]=symbols(lstStrName[index])
index+=1
lsteq=[]
for oneeq in lstSeqs:
eq=sympify(oneeq) #各个字符串方程转换成代码公式
lsteq.append(eq)
#sol = solve([eq1, eq2, eq3], [x, y, z]) # 求解方程组的计算公式
sol = solve(lsteq,lstVarName) # 求解方程组的计算公式:按上行例名变换成动态
sequNum=len(sol) #方程解的数量
if(sequNum==0):
print('本方程没有得到任何解,无计算值结果')
return None
index=1
for sequs in sol:
svalue=str(sequs)
print(f'\n方程第{index}组解是(可能是计算公式):\n{svalue}')
lstxyz = svalue.split(',')
n=0
chgSxyz=''
for sxyz in lstxyz:
count=len(sxyz)
if(count>0):
c1=sxyz[0]
c2=sxyz[count-1]
if(c1=='('):
chgSxyz=sxyz[1:count]
if(c2==')'):
chgSxyz=sxyz[0:count-1]
lstxyz[n]=copy.deepcopy(chgSxyz)
n+=1
#输出方程解的值
id=0
for xyz in lstxyz:
if(xyz.find('I')>0): #解是复数时
print(f'方程第{index}组解:方程变量{lstStrName[id]}复数值={xyz}') #对复数输出复数的值
elif(not isinstance(xyz, (int, float))): #解中包含公式还不是最终的值时
lstVarName[id]=self.countText(xyz) #对非复数值依次计算每个变量的值
print(f'方程第{index}组解:方程变量{lstStrName[id]}={lstVarName[id]}')
else: #方程的解已经是数字了,不需要再经过countText()来计算一道公式
print(f'方程第{index}组解:方程变量{lstStrName[id]}={lstVarName[id]}')
id+=1
index+=1
timeend=time.time()
print(f'\n本次计算共用时:{self.round(timeend-timestart,3)}秒')
return lstxyz
#7、计算椭圆面积
#参数: 长半轴长 短半轴长
def S_elliptic(self,longHelf,sortHelf):
return pi*longHelf*sortHelf
#8、计算扇形面积
#参数:半径或直径,扇形中心角角度(若是弧度要换算)
def S_sector(self,a,deg,rD='R'):
rD=rD.upper()
if rD=='D':a=a/2
return pi*a**2*deg/360
#9、计算扇形弦长和弦高
#参数:半径或直径,扇形中心角角度(若是弧度要换算)
def L_sector(self,a,deg,rD='R'):
rD=rD.upper()
if rD=='D':a=a/2
L= 2*a*sin(self.DegToRad(deg)/2)
h=a*cos(self.DegToRad(deg)/2)
return L,h
#10、计算三角形面积(已知两边夹一角)
#参数:两个边长加一角度(角度单位)
def S_triangle_ab_degC(self,a,b,degC):
return 0.5*a*b*sin(self.DegToRad(degC))
#11、计算三角形面积(已知三条边长)
#参数:三个边长
def S_triangle_abc(self,a,b,c):
p=(a+b+c)/2
return sqrt(p*(p-a)*(p-b)*(p-c))
#12、计算棱形面积(deg=0:已知两对角线长,deg>0:参数表示角度两侧的棱形边长)
#参数:对角线长(deg=0时),或棱形边长(deg>0时),
def S_cuboid_diag(self,a,b,deg=0):
if(deg==0):return a*b/2
else:
c=(a**2+b**2-2*a*b*cos(self.DegToRad(deg)))
d=(a**2+b**2-2*a*b*cos(pi/180-self.DegToRad(deg)))
return c*d/2
#13、计算三角形角度(已知三边,返回三个角度:弧度)
#参数:三个边长
def A_triangle_abc(self,a,b,c):
radA=acos((b**2+c**2-a**2)/(2*b*c))
radB=acos((a**2+c**2-b**2)/(2*a*c))
radC=acos((a**2+b**2-c**2)/(2*a*b))
return radA,radB,radC
#14、计算三角形第三条边长(已知夹一角度:角度)
#参数:a边长,b边长,ab夹角度
def A_triangle_ab_degC(self,a,b,degC):
return sqrt(a**2+b**2-2*a*b*cos(self.DegToRad(degC)))
#15、计算三角形第三条边长(两条边及两条边所对角的角度)
#参数:a边长,a边对角度,b边长,b边对角度
def A_triangle_ab_degC(self,a,degA,b,degB):
radC=self.DegToRad(180)-self.DegToRad(degA)-self.DegToRad(degB)
c=a/sin(self.DegToRad(degA))*sin(radC)
return c
#16、计算圆台体积
#参数:大半径或直径,小半径或直径,高度
def V_frustum(self,a,b,h,rD='R'):
rD=rD.upper()
if rD=='D':
a=a/2
b=b/2
return pi*h*(a**2+b**2+a*b)/3
#17、计算圆台表面积
#参数:大半径或直径,小半径或直径,高度,传入的参数是半径还是直径,面积是否包括上顶和下底面
def S_frustum(self,a,b,h,rD='R',inAllS=True):
rD=rD.upper()
if rD=='D':
a=a/2
b=b/2
S = pi*((a+b)*sqrt(a**2+b**2+h**2))
if(inAllS): S=S+pi*(a**2+b**2)
return S
#18、计算圆柱体积
#参数:半径或直径,高度
def V_cylinder(self,a,h,rD='R'):
rD=rD.upper()
if rD=='D':
a=a/2
return pi*a**2*h
#19、计算圆柱表面积
#参数:半径或直径,高度
def S_cylinder(self,a,b,h,rD='R',inAllS=True):
rD=rD.upper()
if rD=='D':
a=a/2
S = 2*pi*a*h
if(inAllS): S=S+2*pi*a**2
return S
#20、计算圆锥体积
#参数:小半径或直径,高度
def V_cone(self,a,h,rD='R'):
rD=rD.upper()
if rD=='D': a=a/2
return pi*h*(a**2)/3
#21、计算圆锥表面积
#参数:半径或直径,高度
def S_cone(self,a,h,rD='R',inAllS=True):
rD=rD.upper()
if rD=='D': a=a/2
L=sqrt(h**2+a**2)
S= pi*a*(L)
if(inAllS): S=S+pi*a**2
return S
#22、计算球体积
#参数:球半径或直径
def V_cone(self,a,rD='R'):
rD=rD.upper()
if rD=='D': a=a/2
return pi*a*a*a*4/3
#23、计算球表面积
#参数:球半径或直径
def S_cone(self,a,rD='R'):
rD=rD.upper()
if rD=='D': a=a/2
return 4*pi*a*a
#24、计算球冠体积
#参数:球半径或直径,冠高
def V_crown(self,a,h,rD='R'):
rD=rD.upper()
if rD=='D': a=a/2
return (pi/3)*(3*a-h)*h**2
#25、计算球冠表面积
#参数:球半径或直径,b球缺半径,冠高
def S_crown(self,a,b,h,rD='R',inAllS=True):
rD=rD.upper()
if rD=='D': a=a/2
S=2*pi*a*h
if(inAllS): S=S+pi*b**2
return S
#26、计算圆环体积
#参数:环回转半径或直径,环断面半径或直径
def V_segment(self,a,b,rD='R'):
rD=rD.upper()
if rD=='D':
a=a/2
b=b/2
return 2*pi*a*pi*b**2
#27、计算圆环表面积
#参数:环回转半径或直径,环断面半径或直径
def S_segment(self,a,b,rD='R'):
rD=rD.upper()
if rD=='D':
a=a/2
b=b/2
return 2*pi*a*2*pi*b
#######################################################################3
#以下为工程类用计算
#计算两点间的距离(平面时,参数不必传入z1和z2,3D时要传入z1和z2的值)
def L_towPoint(self,x1,y1,x2,y2,z1=0,z2=0):
return sqrt((x2-x1)**2+(y2-y1)**2+(z2-z1)**2)
#计算一直线段中间某一点的高程
#参数:起点到中间点的距离,中间到到终点的距离,起点的高程,终点的高程
def Z_lineTreePoint(L1,L2,z1,z2):
Zx=None
if(z1<=z2):
Zx=z1+L1/(L1+L2)*(z2-z1)
else:
Zx=z2+L2/(L1+L2)*(z1-z2)
return Zx
#计算两点中间某一点的坐标
#参数:起点坐标X1,起点坐标Y1,终点的坐标x2, 终点坐标y2,起点到计算点的距离
def Z_lineTreePoint_XYZ(x1,y1,x2,y2,L1):
pass