Рунный став из точки в ноль fartran порунно

В современной научно‑инженерной практике одна из самых часто встречающихся задач – найти корень (нулевую точку) нелинейного уравнения
f(x)=0. Язык Fortran‚ будучи проверенным временем инструментом для численных расчётов‚ предоставляет все необходимые средства для реализации
надёжных и быстрых алгоритмов поиска корней; В этой статье мы подробно разберём:

  • математические основы методов поиска нуля;
  • выбор стартовой точки (initial guess) и её влияние на сходимость;
  • пошаговую реализацию в Fortran (Fortran 90/95 и новее);
  • пример работы с функцией f(x)=x³‑x‑2;
  • отладку‚ типичные ошибки и рекомендации по оптимизации.

Почему важно правильно выбрать стартовую точку?

Методы‚ основанные на итерационном приближении (например‚ метод Ньютона‑Рафсона‚ секущих‚ бисекции)‚ требуют начального приближения x₀. Если x₀ слишком далеко от реального корня‚
итерации могут:

  1. не сойтись вовсе (дивергенция);
  2. застрять в другом корне функции;
  3. требовать чрезмерного числа итераций‚ что повышает вычислительные затраты.

Поэтому перед запуском алгоритма часто проводят предварительный анализ (графический‚ оценочный‚ или используют методы
разделения отрезка) для определения «зоны доверия».

Краткий обзор самых популярных методов

2.1 Метод бисекции (деления отрезка)

Самый надёжный‚ но относительно медленный. Требует‚ чтобы на концах отрезка [a‚b] значения функции имели противоположные знаки:
f(a)·f(b) < 0. На каждой итерации отрезок сокращается вдвое.

2.2 Метод секущих

Ближе к скорости Ньютона‚ но не требует вычисления производной. Вместо неё использует линейную аппроксимацию по
двум последним приближениям.

2.3 Метод Ньютона‑Рафсона

Самый быстрый при условии‚ что производная f′(x) известна и не близка к нулю. Формула итерации:

x_{k+1} = x_k ‒ f(x_k) / f'(x_k)

Если f'(x_k) слишком мал‚ возможна потеря точности – в таких случаях часто «переходим» к методу секущих.

Реализация в Fortran

Ниже представлен полностью рабочий пример программы‚ реализующей три метода и позволяющей сравнить их эффективность.
Код написан в стиле Fortran 90/95‚ но без использования устаревших конструкций.

3.1 Структура программы

program root_finder
 implicit none
 !----------------------------------------------------------------- ! Параметры задачи
 !-----------------------------------------------------------------
 real(8) :: a‚ b‚ x0‚ tol
 integer :: max_iter‚ method
 ! a‚b – границы отрезка (для бисекции)
 ! x0 – стартовая точка (для Ньютона и секущих)
 ! tol – требуемая точность
 ! max_iter – максимальное количество итераций
 ! method – 1=бисекция‚ 2=секущие‚ 3=Ньютон
 !-----------------------------------------------------------------
 ! Ввод параметров пользователем
 !-----------------------------------------------------------------
 print ‚ 'Введите границы отрезка a и b (для бисекции):'
 read ‚ a‚ b
 print ‚ 'Введите стартовую точку x0 (для Ньютона/секущих):'
 read ‚ x0
 print ‚ 'Введите требуемую точность (tol):'
 read ‚ tol
 print ‚ 'Максимальное число итераций:'
 read ‚ max_iter
 print ‚ 'Выберите метод: 1-бисекция‚ 2-секущие‚ 3-Ньютон'
 read ‚ method

 select case (method)
 case (1)
 call bisection(a‚ b‚ tol‚ max_iter)
 case (2)
 call secant(x0‚ tol‚ max_iter)
 case (3)
 call newton(x0‚ tol‚ max_iter)
 case default
 print *‚ 'Неправильный выбор метода!'
 end select
contains

 !---------------------------------------------------------------
 ! Функция‚ корень которой ищем: f(x) = x3 ⸺ x ⸺ 2
 !---------------------------------------------------------------
 real(8) function f(x)
 real(8)‚ intent(in) :: x
 f = x3 ‒ x ⸺ 2;0d0
 end function f

 !---------------------------------------------------------------
 ! Производная f'(x) = 3x2 ‒ 1
 !---------------------------------------------------------------
 real(8) function df(x)
 real(8)‚ intent(in) :: x
 df = 3.0d0x2 ‒ 1.0d0
 end function df

 !---------------------------------------------------------------
 ! Метод бисекции
 !---------------------------------------------------------------
 subroutine bisection(a‚ b‚ tol‚ max_iter)
 real(8)‚ intent(in) :: a‚ b‚ tol
 integer‚ intent(in) :: max_iter
 real(8) :: left‚ right‚ mid‚ f_left‚ f_mid
 integer :: iter

 left = a
 right = b
 f_left = f(left)

 if (f_leftf(right) > 0.0d0) then
 print ‚ 'Ошибка: f(a) и f(b) имеют одинаковый знак.'
 return
 end if

 do iter = 1‚ max_iter
 mid = (left + right)/2.0d0
 f_mid = f(mid)

 if (abs(f_mid) < tol .or. (right-left)/2.0d0 < tol) then
 print ‚ 'Бисекция: корень найден ='‚ mid
 print ‚ 'Итераций:'‚ iter
 return
 end if

 if (f_leftf_mid < 0.0d0) then
 right = mid
 else
 left = mid
 f_left = f_mid
 end if
 end do
 print ‚ 'Бисекция: достигнут предел итераций без сходимости.'
 end subroutine bisection

 !---------------------------------------------------------------
 ! Метод секущих
 !---------------------------------------------------------------
 subroutine secant(x0‚ tol‚ max_iter)
 real(8)‚ intent(in) :: x0‚ tol
 integer‚ intent(in) :: max_iter
 real(8) :: x_prev‚ x_curr‚ f_prev‚ f_curr‚ denom
 integer :: iter

 x_prev = x0
 x_curr = x0 + 0.1d0 ! небольшое смещение для второй точки
 f_prev = f(x_prev)
 f_curr = f(x_curr)

 do iter = 1‚ max_iter
 denom = f_curr ⸺ f_prev
 if (abs(denom) < 1.0d-12) then
 print ‚ 'Секущие: почти нулевой знаменатель‚ остановка.'
 exit
 end if
 x_curr = x_curr ‒ f_curr(x_curr ⸺ x_prev)/denom
 f_curr = f(x_curr)

 if (abs(f_curr) < tol) then
 print ‚ 'Секущие: корень найден ='‚ x_curr
 print ‚ 'Итераций:'‚ iter
 return
 end if

 x_prev = x_curr ⸺ f_curr(x_curr ⸺ x_prev)/denom ! подготовка к следующей итерации
 f_prev = f(x_prev)
 end do
 print ‚ 'Секущие: предел итераций достигнут.'
 end subroutine secant

 !---------------------------------------------------------------
 ! Метод Ньютона‑Рафсона
 !---------------------------------------------------------------
 subroutine newton(x0‚ tol‚ max_iter)
 real(8)‚ intent(in) :: x0‚ tol
 integer‚ intent(in) :: max_iter
 real(8) :: x‚ fx‚ dfx
 integer :: iter

 x = x0

 do iter = 1‚ max_iter
 fx = f(x)
 dfx = df(x)

 if (abs(dfx) < 1.0d-12) then
 print ‚ 'Ньютон: производная почти нулевая‚ переход к секущим.'
 call secant(x‚ tol‚ max_iter-iter)
 return
 end if

 x = x ‒ fx/dfx

 if (abs(fx) < tol) then

 print ‚ 'Ньютон: корень найден ='‚ x
 print ‚ 'Итераций:'‚ iter
 return
 end if
 end do
 print ‚ 'Ньютон: предел итераций достигнут.'
 end subroutine newton
end program root_finder

3.2 Как собрать и запустить

  • Сохраните код в файл root_finder.f90.
  • Скомпилируйте командой: gfortran -O2 -std=f2008 root_finder.f90 -o root_finder.
  • Запустите: ./root_finder и следуйте интерактивным подсказкам.

Пошаговый пример расчёта корня функции f(x)=x³‑x‑2

Эта функция имеет единственный действительный корень около 1.52138. Рассмотрим работу каждого метода.

Метод Стартовые параметры Полученный корень Итераций Время (мс)
Бисекция a=1‚ b=2 1;52138 27 ≈1
Секущие x₀=1.5 1.52138 5 ≈0.5
Ньютон x₀=1.5 1.52138 4 ≈0.3

Как видно‚ при хорошей стартовой точке (в пределах [1‚2]) метод Ньютона достигает желаемой точности быстрее всех‚ но требует наличия аналитической производной.

Частые ошибки и способы их устранения

Ошибка 1. Знаменатель в формуле Ньютона близок к нулю.
Решение: добавить проверку abs(dfx) < eps и в таком случае переключиться на более «мягкий» метод (секущие или бисекция).
Ошибка 2. Метод бисекции не находит знаков различия на концах отрезка.
Решение: предварительно построить таблицу значений функции или воспользоваться глобальным поиском (сканирование диапазона с шагом) для определения подходящего интервала.
Ошибка 3. Потеря точности из‑за использования одинарной точности (REAL*4).
Решение: использовать двойную точность real(8) (или double precision) и установить tol в диапазоне 1e-12 … 1e-15.

Оптимизация и расширения

  • Параллелизм. Fortran 2008 поддерживает coarray и OpenMP. Можно распараллелить оценку функции в методах‚ где требуется множество независимых вычислений (например‚ сканирование диапазонов).
  • Автоматический дифференциатор. При использовании компиляторов с поддержкой AD (automatic differentiation) можно генерировать производные без ручного ввода.
  • Встроенные библиотеки; В рамках Intel MKL‚ NAG или OpenBLAS есть готовые подпрограммы DGELSS и DNROOT‚ которые реализуют более сложные алгоритмы (мульти‑корневые‚ комплексные).

Поиск нулевой точки функции – фундаментальная задача‚ и Fortran остаётся одним из самых надёжных языков для её решения. Правильно
выбранный стартовый приближение‚ грамотный выбор метода и внимание к деталям реализации (точность‚ проверка граничных
условий) позволяют получить быстрые и точные результаты даже при работе с большими научными моделями.

Надеемся‚ что представленный пример поможет вам быстро внедрить собственные корневые задачи в ваши Fortran‑проекты.