Вот один из примеров использования ООП F2003 для реализации этой идеи. Я начну с модуля, который будет встроен в разделяемую библиотеку:
module solver
implicit none
type, abstract :: curve_t
contains
procedure(func_f), pass(this), deferred :: f
end type curve_t
type :: solver_t
class(curve_t), pointer :: curve
contains
procedure, pass :: solve => solve_root_bisect_method
end type solver_t
abstract interface
function func_f(this, x)
import curve_t
class(curve_t) :: this
real, intent(in) :: x
real :: func_f
end function func_f
end interface
contains
function solve_root_bisect_method(this, a_start, b_start) result(root)
implicit none
class(solver_t) :: this
real, intent(in) :: a_start, b_start
real :: root, c, eps, a, b
integer :: i, imax
imax = 100
eps = 1e-5
a = a_start
b = b_start
do i=1, imax
c = (a+b)/2.
if ( (this%curve%f(c) == 0) .or. ((b-a)/2. < eps)) then
root = c
return
end if
if (sign(1.,this%curve%f(c)) == sign(1.,this%curve%f(a))) then
a = c
else
b = c
end if
end do
! solution did not converge, produce error
root = -999
end function solve_root_bisect_method
end module solver
Это определяет абстрактный класс для представления кривых и класс для решателя. Решатель также можно сделать абстрактным, но для целей демонстрации я решил не делать этого и предоставить один решатель. Вы все еще можете расширить этот тип и предоставить другую процедуру для интерфейса решения. Вы можете скомпилировать это в общую библиотеку, например.
gfortran -shared -fPIC -o solver.so solver.f90
что даст solver.so
и solver.mod
. Я сделал этот дополнительный шаг, чтобы продемонстрировать переносимость и компиляцию без знания каких-либо кривых.
Теперь мы можем представить себя третьим лицом, которое хочет использовать эту удобную библиотеку для поиска корней произвольных кривых. Сначала мы можем определить наш собственный модуль для расширения кривой и предоставления некоторых функций.
module curves
use solver
implicit none
type, extends(curve_t) :: linear_curve
real :: m, b
contains
procedure, pass(this) :: f => f_linear
end type linear_curve
type, extends(curve_t) :: polynomial_curve
real :: a, b, c
contains
procedure, pass(this) :: f => f_polynomial
end type polynomial_curve
contains
real function f_linear(this, x)
use solver
implicit none
class(linear_curve) :: this
real, intent(in) :: x
f_linear = this%m * x + this%b
end function f_linear
real function f_polynomial(this, x)
use solver
implicit none
class(polynomial_curve) :: this
real, intent(in) :: x
f_polynomial = this%a*x*x + this%b*x + this%c
end function f_polynomial
end module curves
Это определяет типы для линейной кривой и полиномиальной кривой, которые содержат свои параметры и функцию для вычисления y
как функции x
с учетом этих параметров. Поскольку мы унаследованы от curve_t
и соответствуем интерфейсу для f
, мы можем легко использовать эти классы с классом solver_t
.
Вот небольшая программа для демонстрации этого
program test
use solver
use curves
implicit none
type(linear_curve), target :: linear
type(polynomial_curve), target :: parabola
type(solver_t) :: root_solver
real :: root
linear%m = 1.
linear%b = 0. ! y=x
parabola%a = 1.
parabola%b = 0.
parabola%c = -1. ! y=x^2-1
root_solver%curve => linear
root = root_solver%solve(-1., 1.)
print *, "root = ", root
root_solver%curve => parabola
root = root_solver%solve(-4., 0.5)
print *, "root1 = ", root
root = root_solver%solve(-0.5, 4.)
print *, "root2 = ", root
end program test
Здесь я объявляю несколько кривых, задаю их параметры и затем вызываю решатель, чтобы найти корень. Если вы скомпилируете наш модуль кривой, тестовую программу и ссылку на общую библиотеку, которую мы создали ранее, мы сможем запустить с выводом:
% ./roots
root = 0.00000000
root1 = -1.00000286
root2 = 1.00000286
(качество корней ограничено качеством решателя примера, который я закинул в первый модуль, можете сделать лучше). Это не лучшая демонстрация чистого объектно-ориентированного программирования, так как классsolver_t можно было бы сделать лучше, но я сосредоточился на демонстрации того, как вы будете подходить к нескольким определяемым пользователем кривым, не зная ничего о них при компиляцииsolve_t.
person
casey
schedule
07.08.2015