Advertisement
Guest User

Untitled

a guest
Apr 14th, 2016
63
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.05 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <math.h>
  3.  
  4. #define DEBUG
  5.  
  6. #define MIN(a, b) ((a) < (b) ? (a) : (b))
  7.  
  8. enum error_status { CONVERGED, INVALID_RANGE, NO_ROOT, NO_CONVERGENCE };
  9.  
  10. typedef struct result_s {
  11. unsigned int iterations;
  12. error_status error;
  13. } result;
  14.  
  15. /*
  16. Linear interpolation to x-axis based on tangent line using derivative
  17.  
  18. x_(n+1) = x_n - f(x_n) / f'(x_n)
  19.  
  20. Small f'(x) leads to poor or no convergence
  21. */
  22. double newton_raphson(double(*f)(double), double(*f_deriv)(double), double x, double tol, unsigned int maxiter, result *r) {
  23. r->iterations = 0;
  24. r->error = CONVERGED;
  25.  
  26. // Check if already given root
  27. if (f(x) == 0) {
  28. return x;
  29. }
  30.  
  31. for (r->iterations = 1; r->iterations < maxiter; r->iterations++) {
  32. r->iterations++;
  33. double x_est = x - f(x) / f_deriv(x);
  34.  
  35. if (f(x_est) == 0 || fabs(x_est - x) <= tol) {
  36. return x_est;
  37. }
  38.  
  39. x = x_est;
  40. }
  41.  
  42. r->error = NO_CONVERGENCE;
  43. return 0;
  44. }
  45.  
  46. /*
  47. Bisection method, use Intermediate Value Theorem over [a, b] to reduce range of root by half iteratively
  48. Replace a or b with (a+b)/2 depending on which one matches sign until interval is sufficiently small
  49.  
  50. Slow convergence, but guaranteed to find a root in [a, b]
  51. */
  52. double bisect(double(*f)(double), double a, double b, double tol, unsigned int maxiter, result *r) {
  53. r->iterations = 0;
  54. r->error = CONVERGED;
  55.  
  56. double fa = f(a);
  57. double fb = f(b);
  58.  
  59. // Check if already given root
  60. if (fa == 0) {
  61. return a;
  62. }
  63. if (fb == 0) {
  64. return b;
  65. }
  66.  
  67. if (fa*fb > 0) {
  68. r->error = INVALID_RANGE;
  69. return 0;
  70. }
  71.  
  72. for (r->iterations = 1; r->iterations < maxiter; r->iterations++) {
  73. double x_est = (b + a) / 2;
  74. double fx_est = f(x_est);
  75.  
  76. if (fx_est * fa > 0) {
  77. a = x_est;
  78. fa = fx_est;
  79. }
  80. else {
  81. b = x_est;
  82. fb = fx_est;
  83. }
  84.  
  85. if (fx_est == 0 || fabs(b - a) <= tol) {
  86. return x_est;
  87. }
  88. }
  89.  
  90. r->error = NO_CONVERGENCE;
  91. return 0;
  92. }
  93.  
  94. /*
  95. Alternative to Newton-Raphson which uses an approximation of the derivative instead
  96.  
  97. Replace f'(x_n) = ( f(x_n) - f(x_(n-1)) ) / ( x_n - x_(n-1) )
  98.  
  99. x_(n+1) = x_n - f(x_n) * ( x_n - x_(n-1) ) / ( f(x_n) - f(x_(n-1)) )
  100. */
  101. double secant(double(*f)(double), double x1, double x2, double tol, unsigned int maxiter, result *r) {
  102. r->iterations = 0;
  103. r->error = CONVERGED;
  104.  
  105. double fx1 = f(x1), fx2 = f(x2);
  106. // Check if already given root
  107. if (fx1 == 0) {
  108. return x1;
  109. }
  110. if (fx2 == 0) {
  111. return x2;
  112. }
  113.  
  114. // Set x1 to be closest to zero
  115. if (fabs(fx1) > fabs(fx2)) {
  116. double swap = x1;
  117. x1 = x2;
  118. x2 = swap;
  119.  
  120. swap = fx1;
  121. fx1 = fx2;
  122. fx2 = swap;
  123. }
  124.  
  125. for (r->iterations = 1; r->iterations < maxiter; r->iterations++) {
  126. double x_est = x1 - fx1 * (x1 - x2) / (fx1 - fx2);
  127. double fx_est = f(x_est);
  128.  
  129. if (fx_est == 0 || fabs(x_est - x1) <= tol) {
  130. return x_est;
  131. }
  132.  
  133. x2 = x1;
  134. fx2 = fx1;
  135. x1 = x_est;
  136. fx1 = fx_est;
  137. }
  138.  
  139. r->error = NO_CONVERGENCE;
  140. return 0;
  141. }
  142.  
  143. /*
  144. Same as secant method, instead of using x_n_prev we use the result x_n estimate
  145. to change the interval to [a, x_n], [x_n, b] depending on which retains the
  146. interval changing sign
  147.  
  148. Slower convergence, but unlike secant method stays within the interval like the bisection method
  149. */
  150. double false_position(double(*f)(double), double a, double b, double tol, unsigned int maxiter, result *r) {
  151. r->iterations = 0;
  152. r->error = CONVERGED;
  153.  
  154. double fa = f(a);
  155. double fb = f(b);
  156. // Check if already given root
  157. if (fa == 0) {
  158. return a;
  159. }
  160. if (fb == 0) {
  161. return b;
  162. }
  163.  
  164. if (fa*fb > 0) {
  165. r->error = INVALID_RANGE;
  166. return 0;
  167. }
  168.  
  169. for (r->iterations = 1; r->iterations < maxiter; r->iterations++) {
  170. double x_est = (a * fb - b * fa) / (fb - fa);
  171. double fx_est = f(x_est);
  172. double del;
  173.  
  174. if (fx_est * fa > 0) {
  175. del = x_est - a;
  176. a = x_est;
  177. fa = fx_est;
  178. }
  179. else {
  180. del = x_est - b;
  181. b = x_est;
  182. fb = fx_est;
  183. }
  184.  
  185. if (fx_est == 0 || fabs(del) < tol) {
  186. return x_est;
  187. }
  188. }
  189.  
  190. r->error = NO_CONVERGENCE;
  191. return 0;
  192. }
  193.  
  194. /*
  195. Ridders' Method is a variation on the false position method,
  196. except instead of using the secant method for the interpolation instead the midpoint
  197. in the interval is calculated and then an exponential factor is removed to linearize the residual
  198. The false position is then applied on f(a), f(mid) e^Q, f(b) e^(2Q)
  199.  
  200. Converges super-linearly and is robust compared to other methods.
  201. */
  202. double ridders(double(*f)(double), double a, double b, double tol, unsigned int maxiter, result *r) {
  203. r->iterations = 0;
  204. r->error = CONVERGED;
  205.  
  206. double fa = f(a);
  207. double fb = f(b);
  208. // Check if already given root
  209. if (fa == 0) {
  210. return a;
  211. }
  212. if (fb == 0) {
  213. return b;
  214. }
  215.  
  216. if (fa*fb > 0) {
  217. r->error = INVALID_RANGE;
  218. return 0;
  219. }
  220.  
  221. for (r->iterations = 1; r->iterations < maxiter; r->iterations++) {
  222. double x_mid = (a + b) / 2;
  223. double fmid = f(x_mid);
  224.  
  225. double x_est = x_mid;
  226. if (fa > fb) {
  227. x_est += (x_mid - a) * fmid / sqrt(fmid*fmid - fa * fb);
  228. }
  229. else {
  230. x_est -= (x_mid - a) * fmid / sqrt(fmid*fmid - fa * fb);
  231. }
  232. double fx_est = f(x_est);
  233.  
  234. double del;
  235. if (fx_est * fa > 0) {
  236. del = a - x_est;
  237. a = x_est;
  238. fa = fx_est;
  239. }
  240. else {
  241. del = b - x_est;
  242. b = x_est;
  243. fb = fx_est;
  244. }
  245.  
  246. if (fx_est == 0 || fabs(del) <= tol) {
  247. return x_est;
  248. }
  249.  
  250. }
  251.  
  252. r->error = NO_CONVERGENCE;
  253. return 0;
  254. }
  255.  
  256. /*
  257. Brent's Method, most common and robust 1D root finding method
  258. Combination of inverse quadratic interpolation, secant method, and bisection method
  259. The method used depends on which one lies within the interval
  260. At worst it converges as fast as the bisection method, and at best quadratically.
  261. */
  262. double brent(double(*f)(double), double a, double b, double tol, unsigned int maxiter, result *r) {
  263. r->iterations = 0;
  264. r->error = CONVERGED;
  265.  
  266. double fa = f(a);
  267. double fb = f(b);
  268. // Check if already given root
  269. if (fa == 0) {
  270. return a;
  271. }
  272. if (fb == 0) {
  273. return b;
  274. }
  275.  
  276. if (fa*fb > 0) {
  277. r->error = INVALID_RANGE;
  278. return 0;
  279. }
  280.  
  281. if (fabs(fa) < fabs(fb)) {
  282. double swap = a;
  283. a = b;
  284. b = swap;
  285.  
  286. swap = fa;
  287. fa = fb;
  288. fb = swap;
  289. }
  290.  
  291. double c = a, fc = fa;
  292. double d = 99e99;
  293. bool mflag = true;
  294.  
  295. for (r->iterations = 1; r->iterations < maxiter; r->iterations++) {
  296. double fc = f(c), s = 0;
  297.  
  298. // quadratic inverse interpolation
  299. if ((fa != fc) && (fb != fc)) {
  300. s += a * fb * fc / (fa - fc) / (fa - fb);
  301. s += b * fc * fa / (fb - fa) / (fb - fc);
  302. s += c * fa * fb / (fc - fb) / (fc - fa);
  303. }
  304. // secant method
  305. else {
  306. s = b - fb * (b - a) / (fb - fa);
  307. }
  308.  
  309. // Determine whether to use bisection step instead, Brent's main contribution to algorithm
  310. // Is ((3a + b) / 4 < s < b) or ((3a + b) / 4 > s > b) ? If no use bisection
  311. // Simplified using De Morgan's Laws
  312. if ((s <= ((3 * a + b) / 4) || s >= b) && (s >= ((3 * a + b) / 4) || s <= b)) {
  313. mflag = true;
  314. s = (a + b) / 2;
  315. }
  316. // test step if we used bisection last time
  317. else if (mflag && ((fabs(s - b) >= (fabs(b - c) / 2)) || (fabs(b - c) < fabs(tol)))) {
  318. mflag = true;
  319. s = (a + b) / 2;
  320. }
  321. // test step if we did not use bisection last time
  322. else if (!mflag && ((fabs(s - b) >= (fabs(c - d) / 2)) || (fabs(c - d) < fabs(tol)))) {
  323. mflag = true;
  324. s = (a + b) / 2;
  325. }
  326. // Continue to use quad interp or secant
  327. else {
  328. mflag = false;
  329. }
  330.  
  331. double fs = f(s);
  332. d = c;
  333. c = b;
  334. fc = fb;
  335.  
  336. if (fa * fs < 0) {
  337. b = s;
  338. fb = fs;
  339. }
  340. else {
  341. a = s;
  342. fa = fs;
  343. }
  344.  
  345. if (fabs(fa) < fabs(fb)) {
  346. double swap = a;
  347. a = b;
  348. b = swap;
  349.  
  350. swap = fa;
  351. fa = fb;
  352. fb = swap;
  353. }
  354.  
  355. if (fb == 0) {
  356. return b;
  357. }
  358.  
  359. if (fs == 0 || fabs(b - a) <= tol) {
  360. return s;
  361. }
  362. }
  363.  
  364. r->error = NO_CONVERGENCE;
  365. return 0;
  366. }
  367.  
  368. double f(double x) {
  369. double y = 3 * pow(x, 3) - 2 * pow(x, 2) + 1 * pow(x, 1) - 5;
  370. return y;
  371. }
  372.  
  373. double f_derive(double x) {
  374. double y = 9 * pow(x, 2) - 4 * pow(x, 1) + 1;
  375. return y;
  376. }
  377.  
  378. double g(double x) {
  379. return (x + 3) * (x - 1) * (x - 1);
  380. }
  381.  
  382. // Derived by Kepler in 1609, one of first transcendental eqs
  383. // Newton used his iterative method by hand to solve
  384. //
  385. double h(double x) {
  386. return x - sin(x) / 2 - 1;
  387. }
  388.  
  389. int main(void) {
  390. result r;
  391. double root;
  392.  
  393. //root = newton_raphson(f, f_derive, 2.0, 1.e-10, 50, &r);
  394. //printf("newton %d steps %f\n", r.iterations, root);
  395. //root = bisect(f, -2, 2, 1.e-10, 50, &r);
  396. //printf("bisect %d steps %f\n", r.iterations, root);
  397. //root = secant(f, 2.0, 2.5, 1.e-10, 50, &r);
  398. //printf("secant %d steps %f\n", r.iterations, root);
  399. //root = false_position(f, -2, 2, 1.e-10, 50, &r);
  400. //printf("false_position %d steps %f\n", r.iterations, root);
  401. //root = ridders(f, -2, 2, 1.e-10, 50, &r);
  402. //printf("ridders %d steps %f\n", r.iterations, root);
  403. //root = brent(f, -2, 2, 1.e-10, 50, &r);
  404. //printf("brent %d steps %f\n", r.iterations, root);
  405.  
  406. //root = brent(g, 4, 5, 1.e-12, 50, &r);
  407. //printf("brent %d steps %f\n", r.iterations, root);
  408.  
  409. root = bisect(h, 0, 2, 1e-10, 50, &r);
  410. printf("bisect - %d steps, %.10f\n", r.iterations, root);
  411. root = secant(h, 0, 2, 1e-10, 50, &r);
  412. printf("secant - %d steps, %.10f\n", r.iterations, root);
  413. root = false_position(h, 0, 2, 1e-10, 50, &r);
  414. printf("false_position - %d steps, %.10f\n", r.iterations, root);
  415. root = ridders(h, 0, 2, 1e-10, 50, &r);
  416. printf("ridders - %d steps, %.10f\n", r.iterations, root);
  417. root = brent(h, 0, 2, 1e-10, 50, &r);
  418. printf("brent - %d steps, %.10f\n", r.iterations, root);
  419.  
  420. getchar();
  421.  
  422. return 0;
  423. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement