метод Брента
В численном анализе метод Брента представляет собой гибридный алгоритм поиска корня, сочетающий в себе метод деления пополам , метод секущего и обратную квадратичную интерполяцию . Он надежен, как разделение пополам, но может быть таким же быстрым, как и некоторые менее надежные методы. Алгоритм пытается использовать потенциально быстро сходящийся метод секущего или обратную квадратичную интерполяцию, если это возможно, но при необходимости он возвращается к более надежному методу деления пополам. Метод Брента принадлежит Ричарду Бренту. [ 1 ] и основан на более раннем алгоритме Теодора Деккера . [ 2 ] Следовательно, этот метод также известен как метод Брента – Деккера .
Современные усовершенствования метода Брента включают метод Чандрупатлы, который проще и быстрее для функций, плоских относительно своих корней; [ 3 ] [ 4 ] Метод Риддерса , который выполняет экспоненциальную интерполяцию вместо квадратичной, обеспечивая более простую замкнутую формулу для итераций; и метод ITP , который представляет собой гибрид правила-ложного и деления пополам, который обеспечивает оптимальные гарантии наихудшего случая и асимптотические гарантии.
метод Деккера
[ редактировать ]Идея объединить метод деления пополам с методом секущих восходит к Деккеру (1969) .
Предположим, что мы хотим решить уравнение f ( x ) = 0. Как и в случае с методом деления пополам, нам нужно инициализировать метод Деккера двумя точками, скажем a 0 и b 0 , такими, что f ( a 0 ) и f ( b 0 ) имеют противоположные знаки. Если f непрерывно на [ a 0 , b 0 ], теорема о промежуточном значении гарантирует существование решения между a 0 и b 0 .
В каждой итерации участвуют три точки:
- b k — текущая итерация, т. е. текущее предположение для корня f .
- a k — это «контраточка», то есть точка такая, что ( ak ) и f ( b k ) имеют противоположные знаки, поэтому интервал [ ak f , b k ] содержит решение. Кроме того, | ж ( б k )| должно быть меньше или равно | f ( a k )|, так что b k является лучшим предположением для неизвестного решения, чем a k .
- b k −1 — предыдущая итерация (для первой итерации мы устанавливаем b k −1 = a 0 ).
Вычисляются два предварительных значения для следующей итерации. Первый из них задается линейной интерполяцией, также известной как метод секущего:
а второй дается методом деления пополам
Если результат метода секущего s лежит строго между b k и m , то он становится следующей итерацией ( b k +1 = s ), в противном случае используется средняя точка ( b k +1 = m ).
Затем значение новой контраточки выбирается такое, чтобы f ( a k +1 ) и f ( b k +1 ) имели противоположные знаки. Если f ( a k ) и f ( b k +1 ) имеют противоположные знаки, то контрапункт остается прежним: a k +1 = a k . В противном случае f ( b k +1 ) и f ( b k ) имеют противоположные знаки, поэтому новая контрапункт становится a k +1 = b k .
Наконец, если | ж ( а k +1 )| < | f ( b k +1 )|, то a k +1, вероятно, является лучшим предположением для решения, чем b k +1 , и, следовательно, значения a k +1 и b k +1 меняются местами.
На этом заканчивается описание одной итерации метода Деккера.
Метод Деккера работает хорошо, если функция f ведет себя достаточно хорошо. Однако бывают случаи, когда на каждой итерации используется метод секущего, но итерации b k сходятся очень медленно (в частности, | b k − b k −1 | может быть сколь угодно малым). В этом случае метод Деккера требует гораздо больше итераций, чем метод деления пополам.
метод Брента
[ редактировать ]Брент (1973) предложил небольшую модификацию, чтобы избежать проблем с методом Деккера. Он вставляет дополнительный тест, который должен быть выполнен, прежде чем результат метода секущего будет принят в качестве следующей итерации. Одновременно должны выполняться два неравенства:
Учитывая конкретный числовой допуск , если на предыдущем шаге использовался метод деления пополам, неравенство должен удерживаться для выполнения интерполяции, в противном случае выполняется метод деления пополам, и его результат используется для следующей итерации.
Если на предыдущем шаге выполнялась интерполяция, то неравенство вместо этого используется для выполнения следующего действия (выбора) интерполяции (когда неравенство истинно) или метода деления пополам (когда неравенство неверно).
Также, если на предыдущем шаге использовался метод деления пополам, неравенство должно выполняться, в противном случае выполняется метод деления пополам, и его результат используется для следующей итерации. Если на предыдущем шаге выполнялась интерполяция, то неравенство вместо этого используется.
Эта модификация гарантирует, что на k-й итерации шаг деления пополам будет выполнен не более чем за дополнительных итераций, поскольку вышеуказанные условия вынуждают размеры последовательных шагов интерполяции уменьшаться вдвое каждые две итерации, и после не более итераций, размер шага будет меньше, чем , который вызывает шаг деления пополам. Брент доказал, что его метод требует не более N 2 итераций, где N обозначает количество итераций метода деления пополам. Если функция f ведет себя хорошо, то метод Брента обычно будет использовать либо обратную квадратичную, либо линейную интерполяцию, и в этом случае он будет сходиться сверхлинейно .
Кроме того, метод Брента использует обратную квадратичную интерполяцию вместо линейной интерполяции (как используется в методе секущего). Если f ( b k ), f ( a k ) и f ( b k −1 ) различны, это немного увеличивает эффективность. Как следствие, условие принятия s (значение, предложенное либо линейной интерполяцией, либо обратной квадратичной интерполяцией) должно быть изменено: s должно лежать между (3 a k + b k ) / 4 и b k .
Алгоритм
[ редактировать ]input a, b, and (a pointer to) a function for f calculate f(a) calculate f(b) if f(a)f(b) ≥ 0 then exit function because the root is not bracketed. end if if |f(a)| < |f(b)| then swap (a,b) end if c := a set mflag repeat until f(b or s) = 0 or |b − a| is small enough (convergence) if f(a) ≠ f(c) and f(b) ≠ f(c) then (inverse quadratic interpolation) else (secant method) end if if (condition 1) s is not between and b or (condition 2) (mflag is set and |s−b| ≥ |b−c|/2) or (condition 3) (mflag is cleared and |s−b| ≥ |c−d|/2) or (condition 4) (mflag is set and |b−c| < |δ|) or (condition 5) (mflag is cleared and |c−d| < |δ|) then (bisection method) set mflag else clear mflag end if calculate f(s) d := c (d is assigned for the first time here; it won't be used above on the first iteration because mflag is set) c := b if f(a)f(s) < 0 then b := s else a := s end if if |f(a)| < |f(b)| then swap (a,b) end if end repeat output b or s (return the root)
Пример
[ редактировать ]Предположим, что мы ищем ноль функции, определяемой формулой f ( x ) = ( x + 3) ( x − 1) 2 .
Мы берем [ a 0 , b 0 ] = [−4, 4/3] в качестве начального интервала.
Имеем f ( a 0 ) = −25 и f ( b 0 ) = 0,48148 (все числа в этом разделе округлены), поэтому условия f ( a 0 ) f ( b 0 ) < 0 и | ж ( б 0 )| ≤ | ж ( а 0 )| удовлетворены.

- На первой итерации мы используем линейную интерполяцию между ( b −1 , f ( b −1 )) = ( a 0 , f ( a 0 )) = (−4, −25) и ( b 0 , f ( b 0 ) )) = (1,33333, 0,48148), что дает s = 1,23256. Оно лежит между (3 a 0 + b 0 ) / 4 и b 0 , поэтому это значение принимается. Кроме того, f (1,23256) = 0,22891, поэтому мы положили a 1 = a 0 и b 1 = s = 1,23256.
- Во второй итерации мы используем обратную квадратичную интерполяцию между ( a 1 , f ( a 1 )) = (−4, −25) и ( b 0 , f ( b 0 )) = (1,33333, 0,48148) и ( b 1 , ж ( б 1 )) = (1,23256, 0,22891). Это дает 1,14205, которое находится между (3 a 1 + b 1 )/4 и b 1 . При этом неравенство |1.14205 − b 1 | ≤ | б 0 - б -1 | / 2 удовлетворено, поэтому это значение принимается. Кроме того, f (1,14205) = 0,083582, поэтому мы полагаем a 2 = a 1 и b 2 = 1,14205.
- На третьей итерации мы используем обратную квадратичную интерполяцию между ( a 2 , f ( a 2 )) = (−4, −25) и ( b 1 , f ( b 1 )) = (1,23256, 0,22891) и ( b 2 , f ( b 2 )) = (1,14205, 0,083582). Это дает 1,09032, которое находится между (3 a 2 + b 2 )/4 и b 2 . Но здесь вступает в силу дополнительное условие Брента: неравенство |1,09032 − b 2 | ≤ | б 1 - б 0 | / 2 не удовлетворено, поэтому это значение отклоняется. средняя точка m = -1,42897 интервала [ a 2 , b 2 Вместо этого вычисляется ]. У нас f ( m ) = 9,26891, поэтому мы положили a 3 = a 2 и b 3 = −1,42897.
- На четвертой итерации мы используем обратную квадратичную интерполяцию между ( a 3 , f ( a 3 )) = (−4, −25) и ( b 2 , f ( b 2 )) = (1,14205, 0,083582) и ( b 3 , f ( b 3 )) = (−1,42897, 9,26891). Это дает 1,15448, что не находится в интервале между (3 a 3 + b 3 )/4 и b 3 ). Следовательно, она заменяется серединой m = −2,71449. У нас f ( m ) = 3,93934, поэтому мы положили a 4 = a 3 и b 4 = −2,71449.
- На пятой итерации обратная квадратичная интерполяция дает −3,45500, что лежит в требуемом интервале. Однако предыдущая итерация была шагом пополам, поэтому неравенство |−3,45500 − b 4 | ≤ | б 4 - б 3 | / 2 должны быть удовлетворены. Это неравенство неверно, поэтому мы используем среднюю точку m = −3,35724. У нас есть f ( m ) = −6,78239, поэтому m становится новой контраточкой ( a 5 = −3,35724 ), а итерация остается той же ( b 5 = b 4 ).
- На шестой итерации мы не можем использовать обратную квадратичную интерполяцию, поскольку b 5 = b 4 . Следовательно, мы используем линейную интерполяцию между ( a 5 , f ( a 5 )) = (-3,35724, -6,78239) и ( b 5 , f ( b 5 )) = (-2,71449, 3,93934). Результат: s = −2,95064, что удовлетворяет всем условиям. Но поскольку итерация не изменилась на предыдущем шаге, мы отвергаем этот результат и возвращаемся к делению пополам. Мы обновляем s = -3,03587 и f ( s ) = -0,58418.
- На седьмой итерации мы снова можем использовать обратную квадратичную интерполяцию. Результат: s = −3,00219, что удовлетворяет всем условиям. Теперь f ( s ) = −0,03515, поэтому мы устанавливаем a 7 = b 6 и b 7 = −3,00219 ( a 7 и b 7 меняются местами так, что условие | f ( b 7 )| ≤ | f ( a 7 ) | удовлетворен). ( Правильно : линейная интерполяция )
- На восьмой итерации мы не можем использовать обратную квадратичную интерполяцию, поскольку a 7 = b 6 . Линейная интерполяция дает s = -2,99994, что принимается. ( Правильно : )
- В следующих итерациях корень x = −3 достигается быстро: b 9 = −3 + 6·10 −8 и b 10 = −3 − 3·10 −15 . ( Правильно : Итер 9: f ( s ) = −1,4 × 10 −7 , Итер 10: ж ( с ) = 6,96 × 10 −12 )
Реализации
[ редактировать ]- Брент (1973) опубликовал реализацию Алгола 60 .
- Netlib содержит перевод этой реализации на Фортран с небольшими изменениями.
- Метод PARI/ GP
solve
реализует метод. - Другие реализации алгоритма (на C++, C и Fortran) можно найти в книгах числовых рецептов .
- Библиотека Apache Commons Math реализует алгоритм на языке Java .
- Модуль оптимизации SciPy реализует алгоритм на Python (языке программирования).
- Стандартная библиотека Modelica реализует алгоритм в Modelica .
- The
uniroot
функция реализует алгоритм в R (программное обеспечение) . - The
fzero
функция реализует алгоритм в MATLAB . - Boost (библиотеки C++) реализует два алгоритма, основанных на методе Брента на C++ в наборе инструментов Math:
- Минимизация функции на сайте minima.hpp с примером поиска функции минимума .
- Поиск корня реализует новый TOMS748, более современный и эффективный алгоритм, чем исходный алгоритм Брента, на TOMS748 , а также поиск корня Boost.Math , который использует TOMS748 внутри себя с примерами .
- Пакет Optim.jl реализует алгоритм на Julia (языке программирования).
- Система компьютерной алгебры Emmy (написанная на Clojure (язык программирования) ) реализует вариант алгоритма, предназначенный для минимизации одномерных функций.
- Поиск корня в библиотеке C#, размещенной в проекте кода.
Ссылки
[ редактировать ]- ^ Брент 1973
- ^ Деккер 1969
- ^ Чандрупатла, Тирупати Р. (1997). «Новый гибридный алгоритм квадратичного деления/бисекции для поиска нуля нелинейной функции без использования производных». Достижения в области инженерного программного обеспечения . 28 (3): 145–149. дои : 10.1016/S0965-9978(96)00051-8 .
- ^ «Десять маленьких алгоритмов, часть 5: Интерполяция квадратичных экстремумов и метод Чандрупатлы - Джейсон Сакс» .
- Брент, Р.П. (1973), «Глава 4: Алгоритм с гарантированной сходимостью для поиска нуля функции», Алгоритмы минимизации без производных , Энглвуд Клиффс, Нью-Джерси: Прентис-Холл, ISBN 0-13-022335-2
- Деккер, Т.Дж. (1969), «Нахождение нуля посредством последовательной линейной интерполяции», в Дежоне, Б.; Хенричи П. (ред.), Конструктивные аспекты фундаментальной теоремы алгебры , Лондон: Wiley-Interscience, ISBN 978-0-471-20300-1
Дальнейшее чтение
[ редактировать ]- Аткинсон, Кендалл Э. (1989). «Раздел 2.8.». Введение в численный анализ (2-е изд.). Джон Уайли и сыновья. ISBN 0-471-50023-2 .
- Пресс, WH; Теукольский, С.А.; Феттерлинг, WT; Фланнери, BP (2007). «Раздел 9.3. Метод Ван Вейнгаардена–Деккера–Брента» . Численные рецепты: искусство научных вычислений (3-е изд.). Нью-Йорк: Издательство Кембриджского университета. ISBN 978-0-521-88068-8 . Архивировано из оригинала 11 августа 2011 г. Проверено 28 февраля 2012 г.
- Алефельд, GE; Потра, ФА; Ши, Исюнь (сентябрь 1995 г.). «Алгоритм 748: Заключение нулей непрерывных функций» . Транзакции ACM в математическом программном обеспечении . 21 (3): 327–344. дои : 10.1145/210089.210111 . S2CID 207192624 .
Внешние ссылки
[ редактировать ]- Zeroin.f в Netlib .
- модуль brent на C++ (также C, Fortran, Matlab). Архивировано 5 апреля 2018 г. в Wayback Machine Джоном Буркардтом.
- Реализация GSL .
- Увеличьте реализацию C++.
- Python (Scipy) Реализация