bisect.scm 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. #| -*-Scheme-*-
  2. Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
  3. 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
  4. 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Massachusetts
  5. Institute of Technology
  6. This file is part of MIT/GNU Scheme.
  7. MIT/GNU Scheme is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or (at
  10. your option) any later version.
  11. MIT/GNU Scheme is distributed in the hope that it will be useful, but
  12. WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with MIT/GNU Scheme; if not, write to the Free Software
  17. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
  18. USA.
  19. |#
  20. ;;;; Root finding by successive bisection
  21. (declare (usual-integrations))
  22. ;;; Simple bisection search
  23. (define (bisect-2 f x0 x1 eps)
  24. (let loop ((x0 x0) (fx0 (f x0)) (x1 x1) (fx1 (f x1)))
  25. (if (= fx0 0.0)
  26. x0
  27. (if (= fx1 0.0)
  28. x1
  29. (if (> (* fx1 fx0) 0.0)
  30. (error "root not bounded")
  31. (let ((xm (/ (+ x0 x1) 2.0)))
  32. (if (close-enuf? x0 x1 eps)
  33. xm
  34. (let ((fxm (f xm)))
  35. (if (< (* fx1 fxm) 0.0)
  36. (loop xm fxm x1 fx1)
  37. (loop x0 fx0 xm fxm))))))))))
  38. #|
  39. ;;; for example
  40. (define (kepler ecc m)
  41. (bisect-2
  42. (lambda (e)
  43. (write-line e)
  44. (- e (* ecc (sin e)) m))
  45. 0.0
  46. 2pi
  47. 1e-15))
  48. (kepler .99 .01)
  49. 6.283185307179586
  50. 0.
  51. 3.141592653589793
  52. 1.5707963267948966
  53. .7853981633974483
  54. ;;; Total of 51 lines here
  55. .34227031649171913
  56. .34227031649176376
  57. .3422703164917861
  58. .3422703164917749
  59. ;Value: .3422703164917749
  60. |#
  61. ;;; Bisection with interpolation
  62. (define (bisect-fp f x0 x1 eps)
  63. (let loop ((x0 x0) (fx0 (f x0)) (x1 x1) (fx1 (f x1)))
  64. (if (= fx0 0.0)
  65. x0
  66. (if (= fx1 0.0)
  67. x1
  68. (if (> (* fx1 fx0) 0.0)
  69. (error "root not bounded")
  70. (let ((xm (/ (- (* fx1 x0) (* fx0 x1)) (- fx1 fx0))))
  71. (if (close-enuf? x0 x1 eps)
  72. xm
  73. (let ((fxm (f xm)))
  74. (if (< (* fx1 fxm) 0.0)
  75. (loop xm fxm x1 fx1)
  76. (loop x0 fx0 xm fxm))))))))))
  77. #|
  78. ;;; for example
  79. (define (kepler ecc m)
  80. (bisect-fp
  81. (lambda (e)
  82. (write-line e)
  83. (- e (* ecc (sin e)) m))
  84. 0.0
  85. 2pi
  86. 1e-15))
  87. (kepler .99 .01)
  88. 6.283185307179586
  89. 0.
  90. .01
  91. .01988423649613729
  92. 2.9653394755776365e-2
  93. 3.9307245802801455e-2
  94. ;;; Total of 536 lines here -- ugh!
  95. .3422703164917746
  96. .3422703164917747
  97. .34227031649177475
  98. .3422703164917748
  99. .34227031649177486
  100. .342270316491775
  101. ;Value: .342270316491775
  102. |#
  103. ;;; Mixed strategy
  104. ;;; for iterations up to *bisect-break* uses midpoint
  105. ;;; for iterations after *bisect-break* uses linear interpolation
  106. (define *bisect-break* 60)
  107. (define *bisect-wallp* #f)
  108. (define* (bisect f x0 x1 eps #:optional n-break)
  109. (let ((n-break (if (default-object? n-break) *bisect-break* n-break)))
  110. (let loop ((x0 x0) (fx0 (f x0)) (x1 x1) (fx1 (f x1)) (iter 0))
  111. (if *bisect-wallp* (write-line (list x0 x1)))
  112. (if (= fx0 0.0)
  113. x0
  114. (if (= fx1 0.0)
  115. x1
  116. (if (> (* fx1 fx0) 0.0)
  117. (error "root not bounded")
  118. (let ((xm (if (< iter n-break)
  119. (/ (+ x0 x1) 2.)
  120. (/ (- (* fx1 x0) (* fx0 x1)) (- fx1 fx0)))))
  121. (if (close-enuf? x0 x1 eps)
  122. xm
  123. (let ((fxm (f xm)))
  124. (if (< (* fx1 fxm) 0.0)
  125. (loop xm fxm x1 fx1 (fix:+ iter 1))
  126. (loop x0 fx0 xm fxm (fix:+ iter 1))))))))))))
  127. #|
  128. ;;; for example
  129. (define (kepler ecc m)
  130. (bisect
  131. (lambda (e)
  132. (write-line e)
  133. (- e (* ecc (sin e)) m))
  134. 0.0
  135. 2pi
  136. 1e-15
  137. 20))
  138. (kepler .99 .01)
  139. 6.283185307179586
  140. 0.
  141. 3.141592653589793
  142. 1.5707963267948966
  143. .7853981633974483
  144. .39269908169872414
  145. .19634954084936207
  146. .2945243112740431
  147. .3436116964863836
  148. .3190680038802134
  149. .3313398501832985
  150. .337475773334841
  151. .3405437349106123
  152. .342077715698498
  153. .3428447060924408
  154. .3424612108954694
  155. .3422694632969837
  156. .3423653370962265
  157. .3423174001966051
  158. .3422934317467944
  159. .34228144752188905
  160. .3422754554094364
  161. .3422703164809715
  162. .34227031649177475
  163. .34227031649177553
  164. ;Value: .34227031649177553
  165. |#
  166. ;;; If we don't know anything, it is usually a good idea to
  167. ;;; break the interval into dx-sized pieces and look for
  168. ;;; roots in each interval.
  169. (define (find-a-root f x0 x1 dx eps continue failure)
  170. (define (find x0 x1)
  171. (if (> (abs (- x0 x1)) dx)
  172. (let ((f1 (f x1)) (f0 (f x0)))
  173. (if (< (* f0 f1) 0)
  174. (continue (bisect f x0 x1 eps))
  175. (let ((xm (/ (+ x0 x1) 2)))
  176. (find x0 xm)
  177. (find xm x1))))
  178. failure))
  179. (find x0 x1))
  180. ;;; Collect the roots found.
  181. (define (search-for-roots f x0 x1 eps small)
  182. (define (find-roots x0 x1)
  183. (let ((f1 (f x1)) (f0 (f x0)))
  184. (if (< (abs (- x1 x0)) small)
  185. (if (< (* f0 f1) 0)
  186. (list (bisect f x0 x1 eps))
  187. '())
  188. (let ((xm (/ (+ x0 x1) 2)))
  189. (append (find-roots x0 xm)
  190. (find-roots xm x1))))))
  191. (find-roots x0 x1))