num_tools.F90 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. module num_tools
  2. implicit none
  3. ! --- in/out -------------------
  4. private
  5. public :: Interval
  6. public :: Swap
  7. contains
  8. !------------------------------------------------------------------
  9. !
  10. ! Computes ileft = max( i, 1 <= i <= n, .and. x(i) < a )
  11. !
  12. ! Input:
  13. ! x: a real sequence of length n, assumed nondecreasing.
  14. ! a: the point whose location with tespect to the sequence
  15. ! x is to be determined.
  16. ! ileft: a 'first guess' estimate of the index to be found.
  17. ! this variable should be set to 1 for the first call to
  18. ! INTERVAL.
  19. ! Interpretate 'ileft' as the interval number {1,..,n-1}
  20. !
  21. ! Output:
  22. ! ileft iflag meaning
  23. ! ------ -------- -------------------------------------
  24. ! 1 -1 a < x(1)
  25. ! i 0 x(i) <= a < x(i+1)
  26. ! n-1 0 a = x( n )
  27. ! n 1 x( n ) < a
  28. !
  29. ! Method:
  30. ! Same as de Boor's INTERV sr, but not using a local index variable to
  31. ! store the last index found. Instead the 'first guess' index LEFT is
  32. ! used to initiate a search for the 'true' LEFT.
  33. !
  34. !------------------------------------------------------------------
  35. subroutine Interval( x, a, ileft, iflag )
  36. ! --- in/out ---------------------------------
  37. real, intent(in) :: x(:)
  38. real, intent(in) :: a
  39. integer, intent(inout) :: ileft
  40. integer, intent(out) :: iflag
  41. ! --- local ----------------------------------
  42. integer :: iright, istep, middle
  43. integer :: n
  44. ! --- begin -----------------------------------
  45. n = size(x)
  46. ! check correctness of first guess:
  47. if ( (ileft < 1) .or. (ileft>n) ) ileft = 1
  48. iright = ileft + 1
  49. if ( iright >= n ) then
  50. if ( a == x(n) ) then
  51. iflag = 0
  52. ileft = n-1
  53. return
  54. else if ( a > x(n) ) then
  55. iflag = 1
  56. ileft = n
  57. return
  58. end if
  59. if ( n <= 1 ) then
  60. iflag = -1
  61. ileft = 1
  62. return
  63. end if
  64. ileft = n-1
  65. iright = n
  66. end if
  67. if ( a >= x(iright) ) then
  68. ! now a >= x(iright). increase iright to capture a.
  69. istep = 1
  70. do
  71. ileft = iright
  72. iright = ileft + istep
  73. if ( iright >= n ) then
  74. if ( a == x(n) ) then
  75. iflag = 0
  76. ileft = n-1
  77. return
  78. else if ( a > x(n) ) then
  79. iflag = 1
  80. ileft = n
  81. return
  82. end if
  83. iright = n
  84. exit
  85. end if
  86. if ( a < x(iright) ) exit
  87. istep = istep*2
  88. end do
  89. else if ( a >= x(ileft) ) then
  90. iflag = 0
  91. return
  92. else
  93. ! now a < x(ileft). decrease ileft to capture a
  94. istep = 1
  95. do
  96. iright = ileft
  97. ileft = iright - istep
  98. if ( ileft <= 1 ) then
  99. ileft = 1
  100. if ( a < x(1) ) then
  101. iflag = -1
  102. ileft = 1
  103. return
  104. end if
  105. exit
  106. end if
  107. if ( a >= x(ileft) ) exit
  108. istep = istep*2
  109. end do
  110. end if
  111. ! now x(ileft) <= x(iright). narrow the interval.
  112. do
  113. middle = ( ileft + iright ) / 2
  114. if ( middle == ileft ) then
  115. iflag = 0
  116. return
  117. end if
  118. if ( a < x(middle) ) then
  119. iright = middle
  120. else
  121. ileft = middle
  122. end if
  123. end do
  124. end subroutine Interval
  125. ! ==========================================================
  126. !
  127. ! call Swap( lx, xx )
  128. !
  129. ! Swaps the elements in array xx with length lx .
  130. !
  131. subroutine Swap( lx, xx )
  132. ! --- in/out -------------------------------
  133. integer, intent(in) :: lx
  134. real, intent(inout) :: xx(lx)
  135. ! --- local --------------------------------
  136. real :: swp
  137. integer :: l
  138. ! --- begin --------------------------------
  139. do l = 1, lx/2
  140. swp = xx(l)
  141. xx(l) = xx(lx-l+1)
  142. xx(lx-l+1) = swp
  143. end do
  144. end subroutine Swap
  145. end module num_tools