Реализация производной на C/C++

Как производная f(x) обычно рассчитывается программно, чтобы обеспечить максимальную точность?

Я реализую метод Ньютона-Рафсона, и он требует получения производной функции .


person vehomzzz    schedule 13.10.2009    source источник
comment
Покажите нам, что вы сделали до сих пор.   -  person Lazarus    schedule 13.10.2009
comment
Вы хотите, чтобы меня уволили :)?   -  person vehomzzz    schedule 13.10.2009
comment
Точность метода Ньютона не зависит (только) от точности производной, подойдет и грубое приближение (в крайнем случае вы получите метод секущих), но будет немного медленнее, чтобы получить ту же точность (больше нужны итерации).   -  person fortran    schedule 13.10.2009


Ответы (8)


Я согласен с @erikkallen в том, что (f(x + h) - f(x - h)) / 2 * h - это обычный подход для численного приближения производных. Однако получить правильный размер шага h немного сложно.

Ошибка аппроксимации в (f(x + h) - f(x - h)) / 2 * h уменьшается по мере того, как h становится меньше, что говорит о том, что вы должны брать h как можно меньше. Но когда h становится меньше, ошибка вычитания с плавающей запятой увеличивается, поскольку числитель требует вычитания почти равных чисел. Если h слишком мало , вы можете потерять большую точность при вычитании. Поэтому на практике вам нужно выбрать не слишком маленькое значение h, которое сводит к минимуму сочетание ошибки аппроксимации и числового ошибка.

Как правило, вы можете попробовать h = SQRT(DBL_EPSILON), где DBL_EPSILON — наименьшее число с двойной точностью e, такое что 1 + e != 1 с машинной точностью. DBL_EPSILON примерно соответствует 10^-15, поэтому вы можете использовать h = 10^-7 или 10^-8.

Дополнительные сведения см. в этих примечаниях по выбору размера шага для дифференциальных уравнений.

person John D. Cook    schedule 13.10.2009
comment
Я думаю, что ваше эмпирическое правило предполагает, что вы используете правило первого порядка для аппроксимации производной. Тем не менее, центральное правило разности, о котором вы упоминаете, - это второй порядок, и соответствующее эмпирическое правило: h = EPSILON ^ (1/3), что составляет примерно 10 ^ (-5) при использовании двойной точности. - person Jitse Niesen; 13.10.2009
comment
Я думаю, что точность можно немного улучшить, разделив на (x+h)-(x-h) вместо 2h. Это математически эквивалентно, но не численно. - person sellibitze; 13.10.2009
comment
Что вы имеете в виду, вместо этого DBL_EPSILON - это наименьшее число двойной точности e, такое что 1 + e != 1 с машинной точностью. - person yves Baumes; 13.10.2009
comment
Выбор h зависит от производной f'''(x). - person Alexey Malistov; 13.10.2009
comment
+1 отличный ответ. Я бы наверняка упустил из виду, что очень маленькие размеры h увеличивают ошибки с плавающей запятой. Спасибо, сегодня я кое-что узнал. - person MAK; 13.10.2009
comment
Как правило, вместо этого возьмите «кубический корень из точности, с которой вы знаете f», умноженной на порядок величины f. Ваша конечная разница порядка 2 имеет усечение + ошибка округления порядка точности (f) ^ 2/3 - person Alexandre C.; 07.09.2011

Newton_Raphson предполагает, что у вас могут быть две функции f(x) и ее производная f'(x). Если у вас нет производной в виде функции и вам нужно оценить производную от исходной функции, вам следует использовать другой алгоритм поиска корня.

Поиск корней в Википедии дает несколько предложений, как и любой текст числового анализа.

person mmmmmm    schedule 13.10.2009

альтернативный текст

альтернативный текст

1) Первый случай:

альтернативный текст

alt text— относительная ошибка округления, около 2^{-16} для double и 2^{-7} для плавать.

Мы можем рассчитать общую ошибку:

альтернативный текст

Предположим, что вы используете двойную плавающую операцию. Таким образом, оптимальное значение h равно 2sqrt(DBL_EPSILON/f''(x)). Вы не знаете f''(x). Но вы должны оценить это значение. Например, если f''(x) около 1, то оптимальное значение h равно 2^{-7}, но если f''(x ) составляет около 10^6, тогда оптимальное значение h равно 2^{-10}!

2) Второй случай:

альтернативный текст

Обратите внимание, что ошибка второго приближения стремится к 0 быстрее, чем ошибка первого. Но если f'''(x) очень большое, то предпочтительнее первый вариант:

альтернативный текст

Обратите внимание, что в первом случае h пропорционально e, а во втором случае h пропорционально e^{1/3}. Для двойных плавающих операций e^{1/3} равно 2^{-5} или 2^{-6}. (Я полагаю, что f'''(x) примерно равно 1).


Какой способ лучше? Неизвестно, если вы не знаете f''(x) и f'''(x) или не можете оценить эти значения. Считается, что второй вариант предпочтительнее. Но если вы знаете, что f'''(x) очень велико, используйте первое.

Каково оптимальное значение h? Предположим, что f''(x) и f'''(x) примерно равны 1. Также предположим, что мы используем двойные плавающие операции. Тогда в первом случае h составляет около 2^{-8}, в первом случае h составляет около 2^{-5}. Исправьте эти значения, если вы знаете f''(x) или f'''(x).

person Community    schedule 13.10.2009
comment
эпсилон должен быть 2^-53 для двойного числа и 2^-24 для числа с плавающей запятой (что составляет около 10^-16 и 10^-7 соответственно). - person Stephen Canon; 13.10.2009
comment
эпсилон - это относительная ошибка округления (не абсолютная). Это всегда около 10 ^ {- 16} для double и 10 ^ -7 для float. - person Alexey Malistov; 13.10.2009
comment
Да, я знаю. В своем ответе вы говорите, что эпсилон - относительная ошибка округления, около 2 ^ {- 16} для двойного числа и 2 ^ {- 7} для числа с плавающей запятой, что явно неверно. Относительная (прямая) ошибка округления также не всегда соответствует этой шкале, а скорее является ошибкой обратного округления. Прямая ошибка может быть намного больше, когда происходит отмена, что, вероятно, произойдет здесь. - person Stephen Canon; 14.10.2009
comment
Образы ImageShack в настоящее время повреждены. - person kibibu; 04.02.2015
comment
Ошибка оценки более правильно кратна abs(f(x))*eps, где кратность относится к количеству операций с плавающей запятой при оценке f(x). Таким образом, h~cbrt(abs(f(x)/f'''(x))*eps) для центральной разницы. - person Lutz Lehmann; 20.06.2018

fprime(x) = (f(x+dx) - f(x-dx)) / (2*dx)

для небольшого dx.

person erikkallen    schedule 13.10.2009
comment
В Numerical Receipes есть комментарии к этому books.google.co.uk/ - person mmmmmm; 13.10.2009

Что вы знаете о f(x)? Если у вас есть только f как черный ящик, единственное, что вы можете сделать, это численно аппроксимировать производную. Но точность обычно не очень.

Вы можете сделать намного лучше, если сможете прикоснуться к коду, вычисляющему f. Попробуйте "автоматическое дифференцирование". Для этого есть несколько хороших библиотек. Применив немного библиотечной магии, вы можете легко преобразовать свою функцию во что-то, что автоматически вычисляет производную. Простой пример C++ см. в разделе исходный код в этом немецком обсуждении.

person sellibitze    schedule 13.10.2009

Вы определенно хотите принять во внимание предложение Джона Кука по выбору h, но обычно вы не хотите использовать центрированную разность для аппроксимации производной. Основная причина заключается в том, что это требует дополнительной оценки функции, если вы используете прямую разницу, т.е.

f'(x) = (f(x+h) - f(x))/h

Тогда вы получите значение f(x) бесплатно, потому что вам нужно вычислить его уже для метода Ньютона. Это не так уж важно, когда у вас есть скалярное уравнение, но если x — вектор, то f'(x) — матрица (якобиан), и вам нужно будет выполнить n дополнительных вычислений функции, чтобы аппроксимировать ее. с использованием метода центрированных разностей.

person MikeT    schedule 14.10.2009

В дополнение к ответу Джона Д. Кука выше важно не только учитывать точность с плавающей запятой, но и надежность функции f (x). Например, в финансах часто случается, что f(x) на самом деле является симуляцией Монте-Карло, а значение f(x) имеет некоторый шум. Использование очень маленького размера шага может в этих случаях сильно ухудшить точность производной.

person Rickard    schedule 13.10.2009

Обычно шум сигнала влияет на качество производной больше, чем что-либо еще. Если у вас есть шум в f(x), Савтицкий-Голей — отличный алгоритм сглаживания, который часто используется для вычисления хороших производных. В двух словах, SG подбирает полином локально к вашим данным, затем этот полином можно использовать для вычисления производной.

Павел

person Paul    schedule 06.11.2009