有两种方法可以解决这个问题:数字和符号。
要以数字方式解决它,您必须首先将其编码为“可运行”函数 - 插入一个值,取出一个值。例如,
def my_function(x):
return 2*x + 6
解析一个字符串来自动创建这样一个函数是很有可能的;假设您将 2x + 6 解析为列表 [6, 2](其中列表索引对应于 x 的幂 - 所以 6*x^0 + 2*x^1)。那么:
def makePoly(arr):
def fn(x):
return sum(c*x**p for p,c in enumerate(arr))
return fn
my_func = makePoly([6, 2])
my_func(3) # returns 12
然后,您需要另一个函数,该函数反复将 x 值插入您的函数,查看结果与想要找到的结果之间的差异,并调整其 x 值以(希望)最小化差异。
def dx(fn, x, delta=0.001):
return (fn(x+delta) - fn(x))/delta
def solve(fn, value, x=0.5, maxtries=1000, maxerr=0.00001):
for tries in xrange(maxtries):
err = fn(x) - value
if abs(err) < maxerr:
return x
slope = dx(fn, x)
x -= err/slope
raise ValueError('no solution found')
这里有很多潜在的问题 - 找到一个好的起始 x 值,假设函数实际上有一个解(即 x^2 + 2 = 0 没有实值答案),达到极限计算精度等。但是在这种情况下,误差最小化函数是合适的,我们得到了很好的结果:
solve(my_func, 16) # returns (x =) 5.000000000000496
请注意,此解决方案并非绝对、完全正确。如果你需要它是完美的,或者如果你想尝试解析方程族,你必须求助于一个更复杂的野兽:一个符号求解器。
符号求解器,如 Mathematica 或 Maple,是一个专家系统,具有许多关于代数、微积分等的内置规则(“知识”);它“知道” sin 的导数是 cos,kx^p 的导数是 kpx^(p-1),依此类推。当您给它一个方程式时,它会尝试找到一条路径,一组规则应用程序,从它所在的位置(方程式)到您想要的位置(方程式的最简单可能形式,希望是解决方案) .
您的示例方程式非常简单;一个象征性的解决方案可能如下所示:
=> LHS([6, 2]) RHS([16])
# rule: pull all coefficients into LHS
LHS, RHS = [lh-rh for lh,rh in izip_longest(LHS, RHS, 0)], [0]
=> LHS([-10,2]) RHS([0])
# rule: solve first-degree poly
if RHS==[0] and len(LHS)==2:
LHS, RHS = [0,1], [-LHS[0]/LHS[1]]
=> LHS([0,1]) RHS([5])
这就是你的解决方案:x = 5。
我希望这能给这个想法带来味道;实施的细节(找到一套好的、完整的规则并决定何时应用每条规则)很容易消耗很多人年的努力。