алгоритм нахождения производной
-
21-09-2019 - |
Вопрос
Я пишу программу на Python, и мне нужно найти производную от функции (функции, выраженной в виде строки).
- Например:
x^2+3*x
- Его производным является:
2*x+3
Есть ли какие-нибудь доступные скрипты или вы можете рассказать мне что-нибудь полезное?
Решение
симпатия делает это хорошо.
Другие советы
Если вы ограничены полиномами (что, по-видимому, так и есть), в основном будет три шага:
- Разобрать входную строку в список коэффициентов до x^n
- Возьмите этот список коэффициентов и преобразуйте его в новый список коэффициентов в соответствии с правилами получения полинома.
- Возьмите список коэффициентов производной и создайте красивую строку, описывающую производную полиномиальную функцию.
Если вам нужно обрабатывать полиномы, такие как a*x^15125 + x^2 + c
, используя dict
список коэффициентов может иметь смысл, но требует немного большего внимания при выполнении итераций по этому списку.
Вы можете найти то, что ищете, в уже предоставленных ответах.Однако я хотел бы дать краткое объяснение того, как вычислять символьные производные.
Бизнес основан на перегрузке операторов и правиле цепочки деривативов.Например, производная от v^n
является n*v^(n-1)dv/dx
, верно?Итак, если у вас есть v=3*x
и n=3
, какой будет производная?Ответ:если f(x)=(3*x)^3
, то производная:
f'(x)=3*(3*x)^2*(d/dx(3*x))=3*(3*x)^2*(3)=3^4*x^2
Правило цепочки позволяет «связать» операцию:каждая отдельная производная проста, и вы просто «связываете» сложность.Другой пример: производная u*v
является v*du/dx+u*dv/dx
, верно?Если вы получаете сложную функцию, вы просто связываете ее, скажем:
d/dx(x^3*sin(x))
u=x^3; v=sin(x)
du/dx=3*x^2; dv/dx=cos(x)
d/dx=v*du+u*dv
Как видите, дифференцирование — это всего лишь цепочка простых операций.
Теперь перегрузка операторов.
Если вы можете написать парсер (попробуйте Pyparsing), вы можете запросить его для оценки как функции, так и производной!Я сделал это (используя Flex/Bison) просто для развлечения, и это довольно мощно.Чтобы вы поняли, производная вычисляется рекурсивно путем перегрузки соответствующего оператора и рекурсивного применения правила цепочки, поэтому вычисление "*"
будет соответствовать u*v для значения функции и u*der(v)+v*der(u)
для производного значения (попробуйте на C++, это тоже весело).
Итак, я знаю, что вы не собираетесь писать свой собственный синтаксический анализатор — во что бы то ни стало используйте существующий код (посетите сайт www.autodiff.org для автоматического различения кода Fortran и C/C++).Но всегда интересно узнать, как эта штука работает.
Ваше здоровье,
Хуан
Символическая дифференциация это впечатляющее введение в предмет - по крайней мере, для неспециалиста вроде меня :) Кстати, код написан на C++.
Искать автоматическое дифференцирование.Есть инструменты для Python.Также, этот.
Лучше поздно, чем никогда?
Я всегда проводил символьную дифференциацию на любом языке, работая с деревом синтаксического анализа.Но недавно мне также стало известно о другом методе, использующем комплексные числа.
Подход к дереву синтаксического анализа состоит в переводе следующего крошечного кода Lisp на любой язык, который вам нравится:
(defun diff (s x)(cond
((eq s x) 1)
((atom s) 0)
((or (eq (car s) '+)(eq (car s) '-))(list (car s)
(diff (cadr s) x)
(diff (caddr s) x)
))
; ... and so on for multiplication, division, and basic functions
))
и после этого добавляйте соответствующий упрощитель, чтобы вы избавились от сложения 0, умножения на 1 и т.д.
Но сложный метод, хотя и полностью числовой, обладает определенным магическим качеством.Вместо того чтобы программировать свое вычисление F с двойной точностью, сделайте это в комплексе двойной точности.Затем, если вам нужна производная вычисления по переменной X, установите для мнимой части X значение очень малого числа h, например 1e-100.Затем выполните вычисление и получите результат R.Теперь real (R) - это результат, который вы обычно получаете, и imag (R) / h = dF / dX с очень высокой точностью!
Как это работает?Возьмем случай умножения комплексных чисел:
(a+bi)(c+di) = ac + i(ad+bc) - bd
Теперь предположим, что все мнимые части равны нулю, за исключением того, что нам нужна производная по отношению к a
.Мы устанавливаем b
до очень небольшого числа h
.Итак, что мы получаем?
(a+hi)(c) = ac + hci
Итак, реальная часть этого заключается в ac
, как и следовало ожидать, и мнимая часть, разделенная на h
, является c
, которая является производной от ac
в отношении a
.
Такого же рода рассуждения, по-видимому, применимы ко всем правилам дифференцирования.
Если вы думаете о написании программы дифференцирования с нуля, не используя в качестве помощи другие библиотеки, то алгоритм/подход вычисления производной любого алгебраического уравнения, который я описал в мой блог будет полезно.
Вы можете попробовать создать класс, который будет строго представлять предел, а затем оценить его для (f(x)-f(a))/(x-a), когда x приближается к a.Это должно дать довольно точное значение предела.
Если только любая уже созданная библиотека не является производной, это довольно сложно, потому что вам нужно анализировать и обрабатывать функции и выражения.
Выведение само по себе является простой задачей, поскольку оно механическое и может быть выполнено алгоритмически, но вам нужна базовая структура для хранения функции.