import numpy as np
import sympy as sp
from scipy.optimize import minimize_scalar
from sympy import Sum, Product, Symbol, oo, Abs, floor, ceiling
import re
class FunctionExtremaAnalyzer:
def __init__(self):
self.x = sp.symbols('x')
self.k = sp.symbols('k') # 求和/连乘索引变量
def parse_input_range(self, range_input):
"""处理输入范围,默认返回(-oo, oo)"""
if not range_input.strip():
return -oo, oo
try:
# 处理各种输入格式:[a,b], (a,b), a b, a,b
range_input = re.sub(r'[\[\]()]', '', range_input)
if ',' in range_input:
x_min, x_max = map(sp.sympify, range_input.split(','))
else:
x_min, x_max = map(sp.sympify, range_input.split())
return x_min, x_max
except:
raise ValueError("范围输入格式无效,请使用[min,max]或留空表示全实数范围")
def preprocess_expression(self, expr_str):
"""预处理表达式字符串,将abs替换为Abs"""
# 替换所有abs(...)为Abs(...)
expr_str = re.sub(r'\babs\s*\(', 'Abs(', expr_str)
return expr_str
def analyze_extrema(self):
print("高级函数极值分析工具")
print("支持功能:三角函数、指数对数、Σ求和、Π连乘、绝对值(Abs)")
print("示例输入:")
print(" sin(x)*Sum(k**2, (k, 1, floor(Abs(x)))) + Abs(x-1)")
print(" Product(cos(k*x), (k, 1, 5)) * exp(-Abs(x))")
while True:
try:
# 输入函数表达式
expr_str = input("\n请输入函数表达式(变量用x表示): ")
expr_str = self.preprocess_expression(expr_str)
# 转换为Sympy表达式
expr = sp.sympify(expr_str, locals={
'Sum': Sum, 'sum': Sum, 'Σ': Sum,
'Product': Product, 'prod': Product, 'Π': Product,
'Abs': Abs, 'abs': Abs,
'floor': floor, 'ceiling': ceiling
})
# 输入范围(默认全实数范围)
range_input = input("请输入范围 [min, max](留空表示全实数范围R): ")
x_min, x_max = self.parse_input_range(range_input)
# 分析表达式特性
has_sum_prod = expr.has(Sum) or expr.has(Product)
has_abs_floor = expr.has(Abs) or expr.has(floor) or expr.has(ceiling)
# 选择分析方法
if has_sum_prod or has_abs_floor:
extrema = self.symbolic_analysis(expr, x_min, x_max)
else:
extrema = self.numeric_analysis(expr, x_min, x_max)
# 显示结果
self.display_results(extrema)
# 询问是否继续
if input("\n是否继续分析其他函数?(y/n): ").lower() != 'y':
break
except Exception as e:
print(f"错误: {str(e)}")
print("请检查输入并重试")
def symbolic_analysis(self, expr, x_min, x_max):
"""符号分析方法,处理含Σ、Π、Abs等的复杂表达式"""
print("\n使用符号分析方法...")
# 处理无限范围
if x_min == -oo or x_max == oo:
print("警告:符号计算需要有限范围,自动设置为[-10,10]")
x_min, x_max = -10, 10
# 计算一阶导数
deriv = sp.diff(expr, self.x)
print(f"导数表达式: {deriv}")
# 求临界点(导数=0的点)
critical_points = []
try:
solutions = sp.solve(deriv, self.x)
critical_points = [sol.evalf() for sol in solutions if sol.is_real]
except:
print("无法解析求解临界点,尝试数值方法")
# 添加不可导点(Abs、floor等函数的转折点)
nondiff_points = self.find_nondifferentiable_points(expr, x_min, x_max)
critical_points.extend(nondiff_points)
# 添加边界点
evaluation_points = critical_points.copy()
evaluation_points.extend([x_min, x_max])
# 计算所有候选点的函数值
extrema = {'min': None, 'max': None}
for point in evaluation_points:
try:
val = expr.subs(self.x, point).evalf()
if not val.is_finite:
continue
val = float(val)
point = float(point)
# 更新最小值
if extrema['min'] is None or val < extrema['min'][1]:
extrema['min'] = (point, val)
# 更新最大值
if extrema['max'] is None or val > extrema['max'][1]:
extrema['max'] = (point, val)
except:
continue
return extrema
def find_nondifferentiable_points(self, expr, x_min, x_max):
"""查找不可导点(如Abs的零点,floor/ceiling的不连续点)"""
points = []
# 查找Abs的参数为零的点
for abs_expr in expr.find(Abs):
arg = abs_expr.args[0]
try:
solution = sp.solve(arg, self.x)
sol = solution[0].evalf()
if x_min <= sol <= x_max:
points.append(sol)
except:
pass
# 查找floor/ceiling的不连续点(整数点)
for fn in [floor, ceiling]:
for fn_expr in expr.find(fn):
arg = fn_expr.args[0]
# 在范围内查找所有使arg为整数的x
try:
# 估算可能的不连续点范围
k_min = int(np.ceil(float(arg.subs(self.x, x_min))))
k_max = int(np.floor(float(arg.subs(self.x, x_max))))
for k in range(k_min, k_max+1):
try:
sol = sp.solve(arg - k, self.x)
if sol:
s = sol[0].evalf()
if x_min <= s <= x_max:
points.append(s)
except:
pass
except:
pass
return points
def numeric_analysis(self, expr, x_min, x_max):
"""数值分析方法,用于常规函数"""
print("\n使用数值分析方法...")
# 转换为数值函数
f = sp.lambdify(self.x, expr, modules=[
'numpy',
{
'sin': np.sin, 'cos': np.cos, 'tan': np.tan,
'exp': np.exp, 'log': np.log, 'sqrt': np.sqrt,
'Abs': np.abs, 'abs': np.abs,
'floor': np.floor, 'ceiling': np.ceil
}
])
# 处理无限范围
if x_min == -oo:
x_min = -1e6
print("自动设置下限为-1e6")
if x_max == oo:
x_max = 1e6
print("自动设置上限为1e6")
# 寻找极值
extrema = {'min': None, 'max': None}
# 寻找最小值
try:
res_min = minimize_scalar(f, bounds=(float(x_min), float(x_max)), method='bounded')
extrema['min'] = (res_min.x, res_min.fun)
except:
pass
# 寻找最大值(通过最小化-f)
try:
res_max = minimize_scalar(lambda x: -f(x), bounds=(float(x_min), float(x_max)), method='bounded')
extrema['max'] = (res_max.x, -res_max.fun)
except:
pass
# 检查边界点
try:
f_min = f(float(x_min))
if extrema['min'] is None or f_min < extrema['min'][1]:
extrema['min'] = (float(x_min), f_min)
if extrema['max'] is None or f_min > extrema['max'][1]:
extrema['max'] = (float(x_min), f_min)
except:
pass
try:
f_max = f(float(x_max))
if extrema['min'] is None or f_max < extrema['min'][1]:
extrema['min'] = (float(x_max), f_max)
if extrema['max'] is None or f_max > extrema['max'][1]:
extrema['max'] = (float(x_max), f_max)
except:
pass
return extrema
def display_results(self, extrema):
"""显示极值结果"""
print("\n分析结果:")
if extrema['min'] is not None:
print(f"最小值: f({extrema['min'][0]:.6f}) = {extrema['min'][1]:.6f}")
else:
print("未找到最小值")
if extrema['max'] is not None:
print(f"最大值: f({extrema['max'][0]:.6f}) = {extrema['max'][1]:.6f}")
else:
print("未找到最大值")
if __name__ == "__main__":
analyzer = FunctionExtremaAnalyzer()
analyzer.analyze_extrema()
按理来说是可以求导的