You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

171 lines
4.1 KiB

25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
  1. // Compute and print the n-th Fibonacci number.
  2. // We work with integers and real numbers.
  3. #include <cln/integer.h>
  4. #include <cln/real.h>
  5. // We do I/O.
  6. #include <cln/io.h>
  7. #include <cln/integer_io.h>
  8. // We use the timing functions.
  9. #include <cln/timing.h>
  10. using namespace std;
  11. using namespace cln;
  12. // F_n is defined through the recurrence relation
  13. // F_0 = 0, F_1 = 1, F_(n+2) = F_(n+1) + F_n.
  14. // The following addition formula holds:
  15. // F_(n+m) = F_(m-1) * F_n + F_m * F_(n+1) for m >= 1, n >= 0.
  16. // (Proof: For fixed m, the LHS and the RHS satisfy the same recurrence
  17. // w.r.t. n, and the initial values (n=0, n=1) agree. Hence all values agree.)
  18. // Replace m by m+1:
  19. // F_(n+m+1) = F_m * F_n + F_(m+1) * F_(n+1) for m >= 0, n >= 0
  20. // Now put in m = n, to get
  21. // F_(2n) = (F_(n+1)-F_n) * F_n + F_n * F_(n+1) = F_n * (2*F_(n+1) - F_n)
  22. // F_(2n+1) = F_n ^ 2 + F_(n+1) ^ 2
  23. // hence
  24. // F_(2n+2) = F_(n+1) * (2*F_n + F_(n+1))
  25. struct twofibs {
  26. cl_I u; // F_n
  27. cl_I v; // F_(n+1)
  28. // Constructor.
  29. twofibs (const cl_I& uu, const cl_I& vv) : u (uu), v (vv) {}
  30. };
  31. // Returns F_n and F_(n+1). Assume n>=0.
  32. static const twofibs fibonacci2 (int n)
  33. {
  34. if (n==0)
  35. return twofibs(0,1);
  36. int m = n/2; // floor(n/2)
  37. twofibs Fm = fibonacci2(m);
  38. // Since a squaring is cheaper than a multiplication, better use
  39. // three squarings instead of one multiplication and two squarings.
  40. cl_I u2 = square(Fm.u);
  41. cl_I v2 = square(Fm.v);
  42. if (n==2*m) {
  43. // n = 2*m
  44. cl_I uv2 = square(Fm.v - Fm.u);
  45. return twofibs(v2 - uv2, u2 + v2);
  46. } else {
  47. // n = 2*m+1
  48. cl_I uv2 = square(Fm.u + Fm.v);
  49. return twofibs(u2 + v2, uv2 - u2);
  50. }
  51. }
  52. // Returns just F_n. Assume n>=0.
  53. const cl_I fibonacci (int n)
  54. {
  55. if (n==0)
  56. return 0;
  57. int m = n/2; // floor(n/2)
  58. twofibs Fm = fibonacci2(m);
  59. if (n==2*m) {
  60. // n = 2*m
  61. // Here we don't use the squaring formula because
  62. // one multiplication is cheaper than two squarings.
  63. cl_I& u = Fm.u;
  64. cl_I& v = Fm.v;
  65. return u * ((v << 1) - u);
  66. } else {
  67. // n = 2*m+1
  68. cl_I u2 = square(Fm.u);
  69. cl_I v2 = square(Fm.v);
  70. return u2 + v2;
  71. }
  72. }
  73. // The next routine is a variation of the above. It is mathematically
  74. // equivalent but implemented in a non-recursive way.
  75. const cl_I fibonacci_compact (int n)
  76. {
  77. if (n==0)
  78. return 0;
  79. cl_I u = 0;
  80. cl_I v = 1;
  81. cl_I m = n/2; // floor(n/2)
  82. for (uintC bit=integer_length(m); bit>0; --bit) {
  83. // Since a squaring is cheaper than a multiplication, better use
  84. // three squarings instead of one multiplication and two squarings.
  85. cl_I u2 = square(u);
  86. cl_I v2 = square(v);
  87. if (logbitp(bit-1, m)) {
  88. v = square(u + v) - u2;
  89. u = u2 + v2;
  90. } else {
  91. u = v2 - square(v - u);
  92. v = u2 + v2;
  93. }
  94. }
  95. if (n==2*m)
  96. // Here we don't use the squaring formula because
  97. // one multiplication is cheaper than two squarings.
  98. return u * ((v << 1) - u);
  99. else
  100. return square(u) + square(v);
  101. }
  102. // Returns just F_n, computed as the nearest integer to
  103. // ((1+sqrt(5))/2)^n/sqrt(5). Assume n>=0.
  104. const cl_I fibonacci_slow (int n)
  105. {
  106. // Need a precision of ((1+sqrt(5))/2)^-n.
  107. float_format_t prec = float_format((int)(0.208987641*n+5));
  108. cl_R sqrt5 = sqrt(cl_float(5,prec));
  109. cl_R phi = (1+sqrt5)/2;
  110. return round1( expt(phi,n)/sqrt5 );
  111. }
  112. #ifndef TIMING
  113. int main (int argc, char* argv[])
  114. {
  115. if (argc != 2) {
  116. cerr << "Usage: fibonacci n" << endl;
  117. return(1);
  118. }
  119. int n = atoi(argv[1]);
  120. cout << "fib(" << n << ") = " << fibonacci(n) << endl;
  121. return(0);
  122. }
  123. #else // TIMING
  124. int main (int argc, char* argv[])
  125. {
  126. int repetitions = 100;
  127. if ((argc >= 3) && !strcmp(argv[1],"-r")) {
  128. repetitions = atoi(argv[2]);
  129. argc -= 2; argv += 2;
  130. }
  131. if (argc != 2) {
  132. cerr << "Usage: fibonacci n" << endl;
  133. return(1);
  134. }
  135. int n = atoi(argv[1]);
  136. { CL_TIMING;
  137. cout << "fib(" << n << ") = ";
  138. for (int rep = repetitions-1; rep > 0; rep--)
  139. fibonacci(n);
  140. cout << fibonacci(n) << endl;
  141. }
  142. { CL_TIMING;
  143. cout << "fib(" << n << ") = ";
  144. for (int rep = repetitions-1; rep > 0; rep--)
  145. fibonacci_compact(n);
  146. cout << fibonacci_compact(n) << endl;
  147. }
  148. { CL_TIMING;
  149. cout << "fib(" << n << ") = ";
  150. for (int rep = repetitions-1; rep > 0; rep--)
  151. fibonacci_slow(n);
  152. cout << fibonacci_slow(n) << endl;
  153. }
  154. return(0);
  155. }
  156. #endif