! Implementation code for stack submodule (rpn_stack) stack_sm implicit none contains module subroutine set_legend_stackt(stk, legend) class(stack_t(*)), intent(inout) :: stk character(len=2), intent(in) :: legend(:) stk%legend = legend end subroutine set_legend_stackt module function get_size_stackt(stk) result(r) class(stack_t(*)), intent(in) :: stk integer :: r r = stk%high_water end function get_size_stackt module subroutine print_stackt(stk, ve_mode) class(stack_t(*)), intent(in) :: stk logical, intent(in) :: ve_mode integer :: i, j if (ve_mode) then do i=stk%high_water,1,-1 write(6,fmt='(a)',advance='no') stk%legend(i)//' ' write(6,'(dt)') stk%sdata(i) end do else write(6,fmt='(dt)') stk%sdata(1) end if end subroutine print_stackt module subroutine push_stackt(stk, z) class(stack_t(*)), intent(inout) :: stk type(rpn_t) :: z integer :: i do i=stk%ssize,2,-1 stk%sdata(i) = stk%sdata(i-1) end do stk%sdata(1) = z if (stk%high_water < stk%ssize) & stk%high_water = stk%high_water + 1 end subroutine push_stackt module subroutine push_r_stackt(stk, x) class(stack_t(*)), intent(inout) :: stk real(8) :: x type(rpn_t) :: z z = rpn_t(cmplx(x,0.0d0)) call stk%push_stackt(z) end subroutine push_r_stackt module subroutine push_all_stackt(stk, z, is_cart) class(stack_t(*)), intent(inout) :: stk complex(8), intent(in) :: z logical, intent(in), optional :: is_cart integer :: i do i=stk%ssize,2,-1 stk%sdata(i) = stk%sdata(i-1) end do if (present(is_cart)) then call stk%set(rpn_t(z,is_cart)) else call stk%set(rpn_t(z)) end if if (stk%high_water < stk%ssize) & stk%high_water = stk%high_water + 1 end subroutine push_all_stackt module subroutine set_stackt(stk, z, idx) class(stack_t(*)), intent(inout) :: stk type(rpn_t), intent(in) :: z integer, optional, intent(in) :: idx if (present(idx)) then stk%sdata(idx) = z else stk%sdata(1) = z end if end subroutine set_stackt module function peek_stackt(stk, idx) result(r) class(stack_t(*)), intent(inout) :: stk integer, intent(in) :: idx type(rpn_t) :: r if (idx >= 1 .and. idx <= stk%ssize) then r = stk%sdata(idx) else write(*,'(a,i0,a)') '***Invalid index (',idx,')' r = rpn_t() end if end function peek_stackt module function pop_stackt(stk) result(r) class(stack_t(*)), intent(inout) :: stk type(rpn_t) :: r integer :: i r = stk%sdata(1) do i=1,stk%ssize-1 stk%sdata(i) = stk%sdata(i+1) end do stk%sdata(stk%ssize) = rpn_t() if (stk%high_water > 0) & stk%high_water = stk%high_water - 1 end function pop_stackt module subroutine clear_stackt(stk) class(stack_t(*)), intent(inout) :: stk integer :: i do i=1,stk%ssize stk%sdata(i) = rpn_t() end do stk%high_water = 0 end subroutine clear_stackt module subroutine swap_stackt(stk) class(stack_t(*)), intent(inout) :: stk integer :: i type(rpn_t) :: z z = stk%sdata(1) stk%sdata(1) = stk%sdata(2) stk%sdata(2) = z end subroutine swap_stackt module subroutine rotate_up_stackt(stk) class(stack_t(*)), intent(inout) :: stk type(rpn_t) :: z z = stk%pop() stk%high_water = stk%high_water + 1 call stk%set(z,stk%high_water) end subroutine rotate_up_stackt module subroutine rotate_down_stackt(stk) class(stack_t(*)), intent(inout) :: stk type(rpn_t) :: z z = stk%peek(stk%high_water) stk%high_water = stk%high_water - 1 call stk%push(z) end subroutine rotate_down_stackt end submodule stack_sm ! Implementation code for rpn_t submodule (rpn_stack) rpn_sm contains module subroutine write_rpns(se, unit, iotype, v_list, iostat, iomsg) class(rpn_t), intent(in) :: se integer, intent(in) :: unit character(*), intent(in) :: iotype integer, intent(in) :: v_list(:) integer, intent(out) :: iostat character(*), intent(inout) :: iomsg complex(8) :: z character(len=:), allocatable :: str_re, str_im iostat = 0 iomsg = "" z = se%zdata if (complex_mode) then call to_string(z%re,str_re) call to_string(z%im,str_im) if (se%is_cartesian()) then write(6,'(a)') '('//str_re//','//str_im//')' else write(6,'(a)') '('//str_re//','//str_im//') p' end if else call to_string(z%re,str_re) write(6,'(a)') str_re end if end subroutine write_rpns ! Convert real to string inserting a leading 0 if necessary module subroutine to_string(x, str) real(8), intent(in) :: x character(len=:), allocatable, intent(out) :: str character(len=32) :: s s = ' ' if (f_small == 'i0') then write(s,fmt='('//f_small//')') nint(x) else if (x == 0 .or. (abs(x) < 1.0d7 .and. abs(x) > 1.0d-7)) then write(s(2:),fmt='('//f_small//')') x else write(s(2:),fmt='('//f_large//')') x end if if (s(2:3) == '-.') then s(1:3) = '-0.' else if (s(2:2) == '.') then s(1:2) = '0.' end if end if str = trim(adjustl(s)) end subroutine to_string module function is_integer_rpns(this) result(r) class(rpn_t), intent(in) :: this logical :: r real(8) :: x x = this%zdata%re r = (abs(nint(x)-x) < eps .and. abs(this%zdata%im) < eps) end function is_integer_rpns module function is_cartesian_rpns(this) result(r) class(rpn_t), intent(in) :: this logical :: r r = this%is_cart end function is_cartesian_rpns module function is_real_rpns(this) result(r) class(rpn_t), intent(in) :: this logical :: r r = this%zdata%im == 0 end function is_real_rpns module function is_positive_real_rpns(this) result(r) class(rpn_t), intent(in) :: this logical :: r r = this%zdata%im == 0 .and. this%zdata%re > 0 end function is_positive_real_rpns module subroutine set_angle_unit_rpns(this, degrees) class(rpn_t), intent(inout) :: this logical, intent(in) :: degrees if (.not. this%is_cart) then this%zdata%im = this%zdata%im*merge(to_deg, to_rad, degrees) end if end subroutine set_angle_unit_rpns module function get_value_rpns(this, is_cartesian) result(r) class(rpn_t), intent(in) :: this logical, optional, intent(out) :: is_cartesian complex(8) :: r r = this%zdata if (present(is_cartesian)) then is_cartesian = this%is_cart end if end function get_value_rpns module subroutine set_value_rpns(this, z, is_cartesian) class(rpn_t), intent(inout) :: this complex(8), optional, intent(in) :: z logical, optional, intent(in) :: is_cartesian if (present(z)) then this%zdata = z end if if (present(is_cartesian)) then this%is_cart = is_cartesian end if end subroutine set_value_rpns module subroutine set_to_rpns(this, z) class(rpn_t), intent(inout) :: this type(rpn_t), intent(in) :: z this%zdata = z%zdata this%is_cart = z%is_cart end subroutine set_to_rpns module function add_rpns(a, b) result(r) class(rpn_t), intent(in) :: a type(rpn_t), intent(in) :: b type(rpn_t) :: r type(rpn_t) :: s logical :: is_cart is_cart = a%is_cartesian() ! The output will be set to this if (a%is_cartesian()) then r = a else r = to_cartesian(a) end if if (b%is_cartesian()) then r%zdata = r%zdata + b%zdata else s = to_cartesian(a) r%zdata = r%zdata + s%zdata end if if (.not. is_cart) then r = to_polar(r) end if end function add_rpns module function subtract_rpns(a, b) result(r) class(rpn_t), intent(in) :: a type(rpn_t), intent(in) :: b type(rpn_t) :: r type(rpn_t) :: s logical :: is_cart is_cart = a%is_cartesian() ! The output will be set to this if (a%is_cartesian()) then r = a else r = to_cartesian(a) end if if (b%is_cartesian()) then r%zdata = r%zdata - b%zdata else s = to_cartesian(a) r%zdata = r%zdata - s%zdata end if if (.not. is_cart) then r = to_polar(r) end if end function subtract_rpns module function multiply_rpns(a, b) result(r) class(rpn_t), intent(in) :: a type(rpn_t), intent(in) :: b type(rpn_t) :: r type(rpn_t) :: s logical :: is_cart is_cart = a%is_cartesian() ! The output will be set to this if (a%is_cartesian()) then r = a else r = to_cartesian(a) end if if (b%is_cartesian()) then r%zdata = r%zdata * b%zdata else s = to_cartesian(a) r%zdata = r%zdata * s%zdata end if if (.not. is_cart) then r = to_polar(r) end if end function multiply_rpns module function divide_rpns(a, b) result(r) class(rpn_t), intent(in) :: a type(rpn_t), intent(in) :: b type(rpn_t) :: r type(rpn_t) :: s logical :: is_cart is_cart = a%is_cartesian() ! The output will be set to this if (a%is_cartesian()) then r = a else r = to_cartesian(a) end if if (b%is_cartesian()) then r%zdata = r%zdata / b%zdata else s = to_cartesian(a) r%zdata = r%zdata / s%zdata end if if (.not. is_cart) then r = to_polar(r) end if end function divide_rpns module function power_rpns(this, x) result(r) class(rpn_t), intent(in) :: this real(8), intent(in) :: x type(rpn_t) :: r type(rpn_t) :: z logical :: is_cart is_cart = this%is_cartesian() if (.not. is_cart) then z = to_cartesian(this) else z = this end if r%zdata = z%zdata**x if (.not. is_cart) then r = to_polar(r) end if end function power_rpns module function to_cartesian_rpns(stk_z) result(r) type(rpn_t), intent(in) :: stk_z type(rpn_t) :: r real(8) :: s real(8) :: theta if (.not. stk_z%is_cartesian()) then s = stk_z%zdata%re theta = stk_z%zdata%im * merge(to_rad,1.0d0,degrees_mode) r%zdata%re = round(s * cos(theta)) r%zdata%im = round(s * sin(theta)) r%is_cart = .true. else r = stk_z end if end function to_cartesian_rpns module function to_polar_rpns(stk_z) result(r) type(rpn_t), intent(in) :: stk_z type(rpn_t) :: r real(8) :: theta if (stk_z%is_cartesian()) then call r%set_value(to_polar_internal(stk_z%get_value()),is_cartesian = .false.) else r = stk_z end if contains complex(8) function to_polar_internal(z) complex(8), intent(in) :: z real(8) :: r real(8) :: theta r = sqrt(real(z * conjg(z),8)) theta = atan2(aimag(z), real(z)) to_polar_internal%re = r to_polar_internal%im = theta * merge(1/to_rad,1.0d0,degrees_mode) end function to_polar_internal end function to_polar_rpns module function add_fr(a,b) result(r) type(rpn_t), intent(in) :: a type(rpn_t), intent(in) :: b type(rpn_t) :: r r = a + b end function add_fr module function subtract_fr(a,b) result(r) type(rpn_t), intent(in) :: a type(rpn_t), intent(in) :: b type(rpn_t) :: r r = a - b end function subtract_fr module function multiply_fr(a,b) result(r) type(rpn_t), intent(in) :: a type(rpn_t), intent(in) :: b type(rpn_t) :: r r = a * b end function multiply_fr module function divide_fr(a,b) result(r) type(rpn_t), intent(in) :: a type(rpn_t), intent(in) :: b type(rpn_t) :: r r = a / b end function divide_fr module function percent_fr(a,b) result(r) type(rpn_t), intent(in) :: a type(rpn_t), intent(in) :: b type(rpn_t) :: r r = a * b / rpn_t(cmplx(100.0d0,0.0d0)) end function percent_fr module function power_fr(a, b) result(r) type(rpn_t), intent(in) :: a type(rpn_t), intent(in) :: b type(rpn_t) :: r r = a ** real(b%zdata) end function power_fr module function power_2_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r r = a ** 2.0d0 end function power_2_fr module function power_3_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r r = a ** 3.0d0 end function power_3_fr module function sqrt_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r call r%set_value(sqrt(a%zdata)) end function sqrt_fr module function cbrt_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r call r%set_value(a%zdata ** (1.0d0/3)) end function cbrt_fr module function reciprocal_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r r = rpn_t(1.0d0)/a end function reciprocal_fr module function conj_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r r = a r%zdata%im = -r%zdata%im end function conj_fr module function len_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r type(rpn_t) :: s s = a * conj_fr(a) r = rpn_t(cmplx(sqrt(real(s%zdata%re)),0.0d0,8)) end function len_fr module function swap_real_imaginary_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r real(8) :: x r = a x = r%zdata%re r%zdata%re = r%zdata%im r%zdata%im = x end function swap_real_imaginary_fr module function chs_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r r = rpn_t(cmplx(-a%zdata%re,-a%zdata%im)) end function chs_fr module function sine_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r r = rpn_t(sin(a%zdata * merge(to_rad,1.0d0,degrees_mode))) end function sine_fr module function cosine_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r r = rpn_t(cos(a%zdata%re * merge(to_rad,1.0d0,degrees_mode))) end function cosine_fr module function tangent_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r r = rpn_t(tan(a%zdata * merge(to_rad,1.0d0,degrees_mode))) end function tangent_fr module function hsine_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r r = rpn_t(sinh(a%zdata)) end function hsine_fr module function hcosine_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r r = rpn_t(cosh(a%zdata)) end function hcosine_fr module function htangent_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r r = rpn_t(tanh(a%zdata)) end function htangent_fr module function asine_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r r = rpn_t(asin(a%zdata) * merge(1/to_rad,1.0d0,degrees_mode)) end function asine_fr module function acosine_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r r = rpn_t(acos(a%zdata) * merge(1/to_rad,1.0d0,degrees_mode)) end function acosine_fr module function atangent_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r r = rpn_t(atan(a%zdata) * merge(1/to_rad,1.0d0,degrees_mode)) end function atangent_fr module function ahsine_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r r = rpn_t(asinh(a%zdata)) end function ahsine_fr module function ahcosine_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r r = rpn_t(acosh(a%zdata)) end function ahcosine_fr module function ahtangent_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r r = rpn_t(atanh(a%zdata)) end function ahtangent_fr module function exp_2_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r r = rpn_t(2**a%zdata) end function exp_2_fr module function exp_e_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r r = rpn_t(exp(a%zdata)) end function exp_e_fr module function exp_10_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r r = rpn_t(10**a%zdata) end function exp_10_fr module function ln_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r r = rpn_t(log(a%zdata)) end function ln_fr module function log2_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r r = rpn_t(log(a%zdata)/log(2.0d0)) end function log2_fr module function lg_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r r = rpn_t(log(a%zdata)/log(10.0d0)) end function lg_fr module function gamma_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r r = rpn_t(gamma(a%zdata%re)) end function gamma_fr module function fact_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r if (a%zdata%re == 0) then r = rpn_t(1) else r = rpn_t(a%zdata%re*gamma(a%zdata%re)) end if end function fact_fr module function ncr_fr(a, b) result(r) type(rpn_t), intent(in) :: a, b type(rpn_t) :: r r = fact_fr(a)/(fact_fr(b)*fact_fr(a-b)) end function ncr_fr module function npr_fr(a, b) result(r) type(rpn_t), intent(in) :: a, b type(rpn_t) :: r r = fact_fr(a)/fact_fr(b) end function npr_fr module function root_fr(a, b) result(r) type(rpn_t), intent(in) :: a type(rpn_t), intent(in) :: b type(rpn_t) :: r real(8) :: bc integer :: i type(rpn_t) :: base complex(8) :: z logical :: a_is_cart real(8) :: s, delta_theta, theta0, phi real(8), parameter :: two_pi = 8*atan(1.0d0) bc = real(b%get_value()) r = power_fr(a, rpn_t(1.0d0/bc)) ! If b is an integer >= 2 calculate all roots if (b%is_integer() .and. bc >= 2) then nroots = nint(bc) if (allocated(roots)) then deallocate(roots) end if a_is_cart = a%is_cartesian() base = to_polar_rpns(a) z = base%get_value() s = z%re ** (1.0d0/bc) theta0 = merge(z%im*to_rad,z%im,degrees_mode)/nroots delta_theta = two_pi/nroots allocate(roots(nroots)) do i=1, nroots phi = theta0 + (i-1)*delta_theta if (a_is_cart) then roots(i) = rpn_t(cmplx(round(s*cos(phi)),round(s*sin(phi))),a_is_cart) else if (degrees_mode) phi = phi*to_deg roots(i) = rpn_t(cmplx(s,round(phi)),a_is_cart) end if end do r = roots(1) current_root = 1 else r = a ** (1.0d0/bc) end if end function root_fr module function next_root_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r if (nroots > 0) then if (current_root == nroots) then current_root = 1 else current_root = current_root + 1 end if r = roots(current_root) else r = a end if end function next_root_fr module function previous_root_fr(a) result(r) type(rpn_t), intent(in) :: a type(rpn_t) :: r if (nroots > 0) then if (current_root == 1) then current_root = nroots else current_root = current_root - 1 end if r = roots(current_root) else r = a end if end function previous_root_fr module function atangent2_fr(a, b) result(r) type(rpn_t), intent(in) :: a type(rpn_t), intent(in) :: b type(rpn_t) :: r r%zdata = atan2(real(a%zdata),real(b%zdata)) * merge(to_deg,1.0d0,degrees_mode) end function atangent2_fr module function round(x) result(r) real(8), intent(in) :: x real(8) :: r if (abs(x) < eps) then r = 0 else r = x end if end function round module subroutine init(lang) character(5), intent(in), optional :: lang if (present(lang)) decimal = lang call set_places(dec_places) end subroutine init module subroutine set_places(n) integer, intent(in) :: n if (n == 0) then f_small = 'i0' else write(f_small,'(2(a,i0),a)') 'f',0,'.',n write(f_large,'(2(a,i0),a)') 'en',10+n,'.',n end if dec_places = n end subroutine set_places module function get_places() result(r) integer :: r r = dec_places end function get_places end submodule rpn_sm