2016-12-03 5 views
-2

Ниже приведен код Python, предназначенный для вычисления производной данной функции f.Какова разница точности между производными расчетами двух версий?

  1. версии один (раствор)

    x[ix] += h # increment by h 
    fxh = f(x) # evalute f(x + h) 
    x[ix] -= 2 * h 
    fxnh = f(x) 
    x[ix] += h 
    numgrad = (fxh - fxnh)/2/h 
    
  2. версии два (моя версия)

    fx = f(x) # evalute f(x) 
    x[ix] += h 
    fxh = f(x) # evalute f(x+h) 
    x[ix] -= h 
    numgrad = (fxh - fx)/h 
    

Она показала версия один дает лучшую точность, может кто-нибудь объяснить, почему это так, в чем разница между двумя вычислениями?

ОБНОВЛЕНИЕ Я не понимаю, что это математическая задача на первом месте, я думал, что это была проблема, связанная с эффектами плавающей точностью. Как было предложено MSeifert, я согласен с тем, что шум поплавкового тома имеет значение, при появлении шума этот результат становится более восприимчивым.

+0

Добро пожаловать в CS.SE! Вообще говоря, код здесь не по теме, и все, что касается Python, вне темы. Часто вопросы кодирования можно задать в разделе «Переполнение стека»; если вы предпочтете переместить свой вопрос там, нажмите «флаг», чтобы отметить это для внимания модератора и попросите моды перенести его. В качестве альтернативы, если это не специфично для Python, замените код математикой или псевдокодом, что будет понятно даже тем, кто не знает Python. (например: Я знаю некоторый Python, но я понятия не имею, что означает 'x [ix]' в этом контексте.) –

+0

Обратите внимание, что утверждение, что первая версия дает лучшую точность, в общем случае не верна. Бывают ситуации, когда одностороннее приближение * математически * выгодно (то есть независимо от арифметики с плавающей запятой вашего компьютера). См., Например, [схемы по ветру] (https://en.wikipedia.org/wiki/Upwind_scheme). Для объяснения, почему первая версия является более точной * в большинстве случаев *, ознакомьтесь с * порядком * [конечных различий] (https://en.wikipedia.org/wiki/Finite_difference). – Phillip

ответ

3

Это не проблема Python, а чисто алгоризм.Предполагая, что функция F имеет хорошие свойства, вы можете посмотреть на его Taylor series развития:

f(x+h) = f(x) + h f'(x) + h*h/2 f"(x) + h*h*h/6 f'''(x) + o(h3) 

Он приходит, что ваша первая форма дает погрешность:

((f(x+h) - f(x))/h) - f'(x) = h/2 f"(x) + o(h) 

, что ошибка в порядке величины Н

Если вы используете вторую форму, вы получите:

((f(x+h) - f(x-h))/2*h) - f'(x) = h*h/3 f'''(x) + o(h2) 

члены в час уже упал, и ошибка в порядке величины ч

Конечно, это имеет смысл, только если существуют необходимые производные ...

0

Ваше решение "one-sided", вы сравниваете f(x+h) - f(x) и общее решение "двустороннее" f(x+h) - f(x-h).

Было бы хорошо, чтобы знать, что такое

It has shown version one gives a better accuracy

средства. Потому что это слишком общее.

Но я думаю, что у меня есть пример, который мог бы быть здесь уместно:

def double_sided_derivative(f, x, h): 
    x_l, x_h = x - h, x + h 
    return (f(x_h) - f(x_l))/2/h 

def one_sided_derivative(f, x, h): 
    x_h = x + h 
    return (f(x_h) - f(x))/h 

h = 1e-8 

def f(x): 
    return 1e-6 * x 

# difference to real derivate: 
double_sided_derivative(f, 10, h) - 1e-6, one_sided_derivative(f, 10, h) - 1e-6 
# (6.715496481486314e-14, 1.5185825954029317e-13) 

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

Используя обе стороны, вы увеличиваете (в зависимости от вашей функции!) Разницу и, следовательно, точку, в которой может произойти отмена. Но, на мой взгляд, самым большим преимуществом является то, что вы учитываете склон с обеих сторон (усредняя его несколько). Например:

h = 1e-6 

def f(x): 
    return 4 + x + 5 * x**2 

def fdx(x): 
    return 1 + 10 * x 

x = 10 

double_sided_derivative(f, x, h) - fdx(x), one_sided_derivative(f, x, h) - fdx(x) 
# (-2.7626811061054468e-08, 4.974594048690051e-06) 

Это намного ближе к истинному значению (на два порядка), чем одностороннее приближение.

+0

Я бы сказал, что самым большим преимуществом является то, что ошибка первой версии находится в 'O (h²)', а другая - в 'O (h) '. – Phillip

+0

@Phillip Я бы сказал, это зависит от функции. В основном я фокусировался на аспекте с плавающей точкой (он был помечен с точностью с плавающей точкой). Или это 'O (h ** 2)' результат арифметики с плавающей запятой? – MSeifert

+0

Это математический результат, который выполняется для всех функций, в которых существует первая и вторая производные, и одна из них относится к математическим объектам, а не к их представлению в компьютере. – Phillip