Получение производной функции в Python

Я написал простой код, который принимает производные, однако он не может взять производную от тригонометрии.

from math import sin, radians def sinus(x): return sin(radians(x)) def derivative(func , x): h = 0.0000000001 return (func(x+h)-func(x))/h def f(x): return 2*x**2+x print(derivative(f, 5)) print(derivative(sinus, 60)) 

Так как производная синуса является косинусом, а косинус (60) равен 0,5, выход должен быть равен

 21.000... 0.5 

но вместо этого он выводит

 21.0000195011 0.00872746319658 

Я что-то делаю неправильно или просто из-за функции math.sin() ?

Что касается небольшой разницы в производной от f() , это происходит из вашей формулы, не являющейся точной. Этот общий разностный фактор дает точный ответ только для бесконечно малого значения h . Компьютер явно не может справиться с бесконечно малым значением, поэтому вы использовали «обычное», но несколько маленькое значение h и вы получили приблизительный ответ. Если вы используете очень маленькое значение h вы получаете другие проблемы из-за того, что компьютер работает только с конечной точностью. Эта точность примерно так же хороша, как вы можете получить с номерами с плавающей запятой с двойной точностью. Существуют более сложные формулы, которые дают лучшие ответы: выполните поиск «числовой производной».

Часто в числовом вычислении нехорошо выполнять вычислительную задачу, как на бумаге. Прежде всего потому, что вы должны беспокоиться о ошибках с плавающей запятой. Таким образом, более эффективная реализация производного определяется следующим образом:

 def derivative(func, x, h = None): if h is None: # Note the hard coded value found here is the square root of the # floating point precision, which can be found from the function # call np.sqrt(np.finfo(float).eps). h = 1.49011611938477e-08 xph = x + h dx = xph - x return (func(xph) - func(x)) / dx 

Посмотрев на это, вы можете возразить и сказать, что dx = h поскольку xph - x = x + h - x = h , однако, если вы действительно выполняете вычисления на компьютере, вы обнаружите, что это неверно, из-за округления. Обратите также внимание на то, что важно выбрать хорошее значение для h чтобы получить наилучший результат. В настоящий момент по умолчанию установлен квадратный корень машинной точности для float в python.

Нет, вы не ошибаетесь в коде.

'd / dx sin (радианы (x))' составляет 1/180 π cos((π x)/180)

http://www.wolframalpha.com/input/?i=d%2Fdx+sin(radians(x))

и что при 60 составляет ~ 0,00872746319658

Синусоидальное производное работает не так, как ожидалось, потому что sinus преобразует часть +h в радианы, а знаменатель оставляет ее в градусах. Вы заметите, что следующая функция правильно вычисляет производную.

 # treat h as degrees def derivative(func, x): h = 0.0000000001 return (func(x + h) - func(x)) / radians(h) derivative(sinus, 60) # 0.5000468070196941 

Или, альтернативно, значение h может быть преобразовано в градусы, прежде чем передавать его в sinus .

 # treat h as radians def derivative(func, x): h = 0.0000000001 return (func(x + degrees(h)) - func(x)) / h derivative(sinus, 60) # 0.5000000413701855 

Обратите внимание, что последняя функция дает более точное значение, потому что радианное значение 0,00 … 01 меньше соответствующего значения степени. Однако оба этих подхода не будут работать для функций, которые не ожидают аргумента в градусах.

Единственный способ решить эту проблему – указать, находится ли вход в градусах, и даже это может не работать для более сложных тригонометрических уравнений (поскольку при дифференцировании уравнений при выражении в градусах появляются всплески мощности π / 180).

 def derivative(func, x, trans=lambda x: x): h = 0.0000000001 return (func(x + trans(h)) - func(x)) / h derivative(sinus, 60, degrees) # 0.5000000413701855