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.

143 lines
3.4 KiB

25 years ago
  1. // Compute and print the n-th Fibonacci number.
  2. // We work with integers and real numbers.
  3. #include <cl_integer.h>
  4. #include <cl_real.h>
  5. // We do I/O.
  6. #include <cl_io.h>
  7. #include <cl_integer_io.h>
  8. // We use the timing functions.
  9. #include <cl_timing.h>
  10. // Declare the exit() function.
  11. #include <stdlib.h>
  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. // Returns just F_n, computed as the nearest integer to
  74. // ((1+sqrt(5))/2)^n/sqrt(5). Assume n>=0.
  75. const cl_I fibonacci_slow (int n)
  76. {
  77. // Need a precision of ((1+sqrt(5))/2)^-n.
  78. cl_float_format_t prec = cl_float_format((int)(0.208987641*n+5));
  79. cl_R sqrt5 = sqrt(cl_float(5,prec));
  80. cl_R phi = (1+sqrt5)/2;
  81. return round1( expt(phi,n)/sqrt5 );
  82. }
  83. #ifndef TIMING
  84. int main (int argc, char* argv[])
  85. {
  86. if (argc != 2) {
  87. fprint(cl_stderr, "Usage: fibonacci n\n");
  88. exit(1);
  89. }
  90. int n = atoi(argv[1]);
  91. fprint(cl_stdout, "fib(");
  92. fprintdecimal(cl_stdout, n);
  93. fprint(cl_stdout, ") = ");
  94. fprint(cl_stdout, fibonacci(n));
  95. fprint(cl_stdout, "\n");
  96. }
  97. #else // TIMING
  98. int main (int argc, char* argv[])
  99. {
  100. int repetitions = 1;
  101. if ((argc >= 3) && !strcmp(argv[1],"-r")) {
  102. repetitions = atoi(argv[2]);
  103. argc -= 2; argv += 2;
  104. }
  105. if (argc != 2) {
  106. fprint(cl_stderr, "Usage: fibonacci n\n");
  107. exit(1);
  108. }
  109. int n = atoi(argv[1]);
  110. { CL_TIMING;
  111. fprint(cl_stdout, "fib(");
  112. fprintdecimal(cl_stdout, n);
  113. fprint(cl_stdout, ") = ");
  114. for (int rep = repetitions-1; rep > 0; rep--)
  115. fibonacci(n);
  116. fprint(cl_stdout, fibonacci(n));
  117. fprint(cl_stdout, "\n");
  118. }
  119. { CL_TIMING;
  120. fprint(cl_stdout, "fib(");
  121. fprintdecimal(cl_stdout, n);
  122. fprint(cl_stdout, ") = ");
  123. for (int rep = repetitions-1; rep > 0; rep--)
  124. fibonacci_slow(n);
  125. fprint(cl_stdout, fibonacci_slow(n));
  126. fprint(cl_stdout, "\n");
  127. }
  128. }
  129. #endif