numeric.nim 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2013 Robert Persson
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## **Warning:** This module will be moved out of the stdlib and into a
  10. ## Nimble package, don't use it.
  11. type OneVarFunction* = proc (x: float): float
  12. {.deprecated: [TOneVarFunction: OneVarFunction].}
  13. proc brent*(xmin,xmax:float, function:OneVarFunction, tol:float,maxiter=1000):
  14. tuple[rootx, rooty: float, success: bool]=
  15. ## Searches `function` for a root between `xmin` and `xmax`
  16. ## using brents method. If the function value at `xmin`and `xmax` has the
  17. ## same sign, `rootx`/`rooty` is set too the extrema value closest to x-axis
  18. ## and succes is set to false.
  19. ## Otherwise there exists at least one root and success is set to true.
  20. ## This root is searched for at most `maxiter` iterations.
  21. ## If `tol` tolerance is reached within `maxiter` iterations
  22. ## the root refinement stops and success=true.
  23. # see http://en.wikipedia.org/wiki/Brent%27s_method
  24. var
  25. a=xmin
  26. b=xmax
  27. c=a
  28. d=1.0e308
  29. fa=function(a)
  30. fb=function(b)
  31. fc=fa
  32. s=0.0
  33. fs=0.0
  34. mflag:bool
  35. i=0
  36. tmp2:float
  37. if fa*fb>=0:
  38. if abs(fa)<abs(fb):
  39. return (a,fa,false)
  40. else:
  41. return (b,fb,false)
  42. if abs(fa)<abs(fb):
  43. swap(fa,fb)
  44. swap(a,b)
  45. while fb!=0.0 and abs(a-b)>tol:
  46. if fa!=fc and fb!=fc: # inverse quadratic interpolation
  47. s = a * fb * fc / (fa - fb) / (fa - fc) + b * fa * fc / (fb - fa) / (fb - fc) + c * fa * fb / (fc - fa) / (fc - fb)
  48. else: #secant rule
  49. s = b - fb * (b - a) / (fb - fa)
  50. tmp2 = (3.0 * a + b) / 4.0
  51. if not((s > tmp2 and s < b) or (s < tmp2 and s > b)) or
  52. (mflag and abs(s - b) >= (abs(b - c) / 2.0)) or
  53. (not mflag and abs(s - b) >= abs(c - d) / 2.0):
  54. s=(a+b)/2.0
  55. mflag=true
  56. else:
  57. if (mflag and (abs(b - c) < tol)) or (not mflag and (abs(c - d) < tol)):
  58. s=(a+b)/2.0
  59. mflag=true
  60. else:
  61. mflag=false
  62. fs = function(s)
  63. d = c
  64. c = b
  65. fc = fb
  66. if fa * fs<0.0:
  67. b=s
  68. fb=fs
  69. else:
  70. a=s
  71. fa=fs
  72. if abs(fa)<abs(fb):
  73. swap(a,b)
  74. swap(fa,fb)
  75. inc i
  76. if i>maxiter:
  77. break
  78. return (b,fb,true)