Как я могу решить уравнения в Python?

Допустим, у меня есть уравнение:

2x + 6 = 12

С помощью алгебры мы можем видеть, что x = 3. Как я могу написать программу на Python, которая может решать x? Я новичок в программировании, и я смотрел на eval() и exec(), но я не могу понять, как заставить их делать то, что я хочу. Я не хочу использовать внешние библиотеки (например, SAGE), я хочу сделать это на простом Python.


person user1221937    schedule 08.05.2012    source источник
comment
Если вы хотите решить какое-либо уравнение, вам придется создать собственную библиотеку. Также 4,5 секунды недостаточно для этого примера: D   -  person jamylak    schedule 08.05.2012
comment
Всегда ли проблемы будут выглядеть как solve y = mx + c for x?   -  person Li-aung Yip    schedule 08.05.2012
comment
@MikePennington: если он хочет разрешить только очень ограниченный набор уравнений, это вполне выполнимо. В абстрактном случае, конечно, вам пришлось бы создавать свой собственный символьный математический движок а-ля maxima или Mathematica, но я не думаю, что это является целью.   -  person Li-aung Yip    schedule 08.05.2012


Ответы (5)


Как насчет SymPy? Их решатель выглядит так, как вам нужно. Взгляните на их исходный код, если вы хотите собрать библиотеку самостоятельно…

person eumiro    schedule 08.05.2012
comment
Забавно видеть такой ответ через несколько минут после всех ехидных комментариев к вопросу :D - person naught101; 30.01.2015

Есть два способа подойти к этой задаче: численно и символически.

Чтобы решить ее численно, вы должны сначала закодировать ее как "исполняемую" функцию - вставить значение, получить значение. Например,

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.

Я надеюсь, что это дает аромат идеи; детали реализации (нахождение хорошего, полного набора правил и принятие решения о том, когда следует применять каждое правило) могут легко потребовать многих человеко-лет усилий.

person Hugh Bothwell    schedule 08.05.2012

Питон может быть хорош, но это не Бог...

Существует несколько различных способов решения уравнений. SymPy уже упоминался, если вы ищете аналитические решения.

Если вас устраивает просто числовое решение, у Numpy есть несколько подпрограмм, которые могут вам помочь. Если вас просто интересуют решения многочленов, вам подойдет numpy.roots. Конкретно для случая, который вы упомянули:

>>> import numpy
>>> numpy.roots([2,-6])
array([3.0])

Для более сложных выражений взгляните на scipy.fsolve.

В любом случае, вы не можете избежать использования библиотеки.

person Pascal Bugnion    schedule 08.05.2012
comment
Если вы не разбираетесь в своих численных методах, вы не сможете этого сделать, что в любом случае может привести к худшему результату, чем в какой-либо надежной библиотеке. - person zardilior; 05.01.2020

Если вы хотите решить только чрезвычайно ограниченный набор уравнений mx + c = y для положительного целого числа m, c, y, то подойдет следующее:

import re
def solve_linear_equation ( equ ):
    """
    Given an input string of the format "3x+2=6", solves for x.
    The format must be as shown - no whitespace, no decimal numbers,
    no negative numbers.
    """
    match = re.match(r"(\d+)x\+(\d+)=(\d+)", equ)
    m, c, y = match.groups()
    m, c, y = float(m), float(c), float(y) # Convert from strings to numbers
    x = (y-c)/m
    print ("x = %f" % x)

Некоторые тесты:

>>> solve_linear_equation("2x+4=12")
x = 4.000000
>>> solve_linear_equation("123x+456=789")
x = 2.707317
>>> 

Если вы хотите распознавать и решать произвольные уравнения, такие как sin(x) + e^(i*pi*x) = 1, вам потребуется реализовать какой-либо символьный математический движок, подобный maxima, Mathematica, MATLAB solve() или Symbolic Toolbox и т. д. Как новичок , это вне вашего понимания.

person Li-aung Yip    schedule 08.05.2012

Используйте другой инструмент. Что-то вроде Wolfram Alpha, Maple, R, Octave, Matlab или любой другой программный пакет для алгебры.

Как новичок, вы, вероятно, не должны пытаться решить такую ​​нетривиальную задачу.

person Community    schedule 08.05.2012