Loading [MathJax]/extensions/tex2jax.js
MRFFL: MR Fortran Finance Library 2024-12-28
Computational Tools For Finance
All Namespaces Files Functions Variables
mrffl_solver.f90
Go to the documentation of this file.
1! -*- Mode:F90; Coding:us-ascii-unix; fill-column:129 -*-
2!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!.H.S.!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!.H.E.!!
3!>
4!! @file mrffl_solver.f90
5!! @author Mitch Richling http://www.mitchr.me/
6!! @date 2024-12-19
7!! @brief Root solvers.@EOL
8!! @keywords finance fortran monte carlo inflation cashflow time value of money tvm percentages taxes stock market
9!! @std F2023
10!! @see https://github.com/richmit/FortranFinance
11!! @copyright
12!! @parblock
13!! Copyright (c) 2024, Mitchell Jay Richling <http://www.mitchr.me/> All rights reserved.
14!!
15!! Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
16!! conditions are met:
17!!
18!! 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following
19!! disclaimer.
20!!
21!! 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following
22!! disclaimer in the documentation and/or other materials provided with the distribution.
23!!
24!! 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products
25!! derived from this software without specific prior written permission.
26!!
27!! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
28!! INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29!! DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30!! EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
31!! USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32!! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33!! OF THE POSSIBILITY OF SUCH DAMAGE.
34!! @endparblock
35!!
36
37!----------------------------------------------------------------------------------------------------------------------------------
38!> Root solvers.
39!!
41 use mrffl_config, only: rk=>mrfflrk, ik=>mrfflik
42 implicit none
43 private
44
45 public :: bisection, multi_bisection
46
47contains
48
49 !------------------------------------------------------------------------------------------------------------------------------
50 !> Search for a root for the function f in the interval [x0_init, x1_init].
51 !!
52 !! The process is iterative. At each step the size of the search interval is cut in half. If the search interval gets too
53 !! small (< x_epsilon), then the process is abandoned. If no zero is found after max_itr, then the process is abandoned.
54 !!
55 !! @param xc The solution (or last value tested if no solution is found)
56 !! @param x0_init Left side of search interval
57 !! @param x1_init Right side of search interval
58 !! @param f Function to solve for zero
59 !! @param x_epsilon Used to test if current search interval is too small
60 !! @param y_epsilon Used to test if f is near zero
61 !! @param max_itr Maximum number of iterations before giving up
62 !! @param status Returns status of computation. 0 if everything worked. Range: 0 & 4001-4032.
63 !! @param progress Print progress as solver searches for a solution
64 !!
65 subroutine bisection(xc, x0_init, x1_init, f, x_epsilon, y_epsilon, max_itr, status, progress)
66
67 interface
68 real(kind=rk) function func_to_solve_t(x)
69 use mrffl_config, only: rk=>mrfflrk, ik=>mrfflik
70 implicit none
71 real(kind=rk), intent(in) :: x
72 end function func_to_solve_t
73 end interface
74
75 procedure(func_to_solve_t) :: f
76 real(kind=rk), intent(out) :: xc
77 real(kind=rk), intent(in) :: x0_init, x1_init
78 real(kind=rk), intent(in) :: x_epsilon, y_epsilon
79 integer(kind=ik), intent(in) :: max_itr
80 integer(kind=ik), intent(out) :: status
81 logical, intent(in) :: progress
82 real(kind=rk) :: x0, x1, f0, f1, fc
83 integer(kind=ik) :: itr
84
85 x0 = x0_init
86 xc = x0
87 f0 = f(xc)
88 if (abs(f0) < y_epsilon) then
89 status = 0
90 else
91 x1 = x1_init
92 xc = x1
93 f1 = f(xc)
94 if (abs(f1) < y_epsilon) then
95 xc = x1
96 status = 0
97 else
98 if (progress) print *, 0, x0, f0, x1, f1
99 if (((f0 < 0) .and. (f1 < 0)) .or. ((f0 > 0) .and. (f1 > 0))) then
100 status = 4001 ! "ERROR(bisection): f is the same sign on initial interval endpoints!"
101 else
102 do itr=1,max_itr
103 xc = (x0 + x1) / 2
104 if (abs(x0-x1) < x_epsilon) then
105 status = 4002 ! "ERROR(bisection): Interval is smaller than x_epsilon!"
106 end if
107 fc = f(xc)
108 if (progress) print *, itr, x0, f0, x1, f1, xc, fc
109 if (abs(fc) < y_epsilon) then
110 status = 0
111 return
112 end if
113 if (fc < 0) then
114 if (f0 < 0) then ! && (f1 > 0)
115 x0 = xc
116 f0 = fc
117 else ! (f0 > 0) && (f1 < 0)
118 x1 = xc
119 f1 = fc
120 end if
121 else ! (f>0)
122 if (f0 < 0) then ! && (f1 > 0)
123 x1 = xc
124 f1 = fc
125 else ! (f0 > 0) && (f1 < 0)
126 x0 = xc
127 f0 = fc
128 end if
129 end if
130 end do
131 status = 4003 ! "ERROR(bisection): Failed to converge!"
132 end if
133 end if
134 end if
135 end subroutine bisection
136
137 !------------------------------------------------------------------------------------------------------------------------------
138 !> Use bisection() to search for a root for the function f in a list of intervals returning the first root found.
139 !!
140 !! @param xc The solution (or last value tested if no solution is found)
141 !! @param x0_init A *VECTOR* of left sides for search intervals
142 !! @param x1_init A *VECTOR* of right sides for search intervals
143 !! @param f Function to solve for zero
144 !! @param x_epsilon Used to test if current search interval is too small
145 !! @param y_epsilon Used to test if f is near zero
146 !! @param max_itr Maximum number of iterations before giving up
147 !! @param status Returns status of computation. 0 if everything worked. Range: 0 & 4033-4064.
148 !! @param progress Print progress as solver searches for a solution
149 !!
150 subroutine multi_bisection(xc, x0_init, x1_init, f, x_epsilon, y_epsilon, max_itr, status, progress)
151 implicit none
152
153 interface
154 real(kind=rk) function func_to_solve_t(x)
155 use mrffl_config, only: rk=>mrfflrk, ik=>mrfflik
156 implicit none
157 real(kind=rk), intent(in) :: x
158 end function func_to_solve_t
159 end interface
160
161 procedure(func_to_solve_t) :: f
162 real(kind=rk), intent(out) :: xc
163 real(kind=rk), intent(in) :: x0_init(:), x1_init(:)
164 real(kind=rk), intent(in) :: x_epsilon, y_epsilon
165 integer(kind=ik), intent(in) :: max_itr
166 integer(kind=ik), intent(out) :: status
167 logical, intent(in) :: progress
168 integer(kind=ik) :: interval, num_intervals
169
170 num_intervals = size(x0_init, kind=ik)
171 do interval=1,num_intervals
172 if (progress) print *, "Bisection on [", x0_init(interval), ", ", x1_init(interval), "]"
173 call bisection(xc, x0_init(interval), x1_init(interval), f, x_epsilon, y_epsilon, max_itr, &
174 status, progress)
175 if (status == 0) then
176 return
177 end if
178 end do
179 status = 4033 ! "ERROR(bisection): No root found in any interval!"
180 end subroutine multi_bisection
181
182end module mrffl_solver
Configuration for MRFFL (MR Fortran Finance Library).
integer, parameter, public mrfflrk
Real kind used in interfaces.
integer, parameter, public mrfflik
Integer kinds used in interfaces.
Root solvers.
subroutine, public multi_bisection(xc, x0_init, x1_init, f, x_epsilon, y_epsilon, max_itr, status, progress)
Use bisection() to search for a root for the function f in a list of intervals returning the first ro...
subroutine, public bisection(xc, x0_init, x1_init, f, x_epsilon, y_epsilon, max_itr, status, progress)
Search for a root for the function f in the interval [x0_init, x1_init].