home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung 2 / Power-Programmierung CD 2 (Tewi)(1994).iso / gnu / djgpp / src / libgplus.5 / libgplus / etc / fib / fib.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-26  |  13.5 KB  |  613 lines

  1. #include <stream.h>
  2. #include <Integer.h>
  3. #include <builtin.h>
  4.  
  5. // Fun and games with the Fibonacci function.
  6. // Also demonstrates use of the `named return value' extension.
  7.  
  8. // fib1 and fib2 from Doug Lea, others from Doug Schmidt.
  9.  
  10. /**********************************************************************/
  11.  
  12. // Standard iterative version:
  13.  
  14. // Schmidt uses convention that fib(0) = 1, not fib(0) = 0;
  15. // so I just increment n here.
  16.  
  17. Integer 
  18. fib1(int n)
  19. {
  20.   ++n;
  21.   if (n <= 0)
  22.     return 0;
  23.   else
  24.     {
  25.       Integer f = 1;
  26.       Integer prev = 0;
  27.  
  28.       while (n > 1)
  29.         {
  30.           Integer tmp = f;
  31.           f += prev;
  32.           prev = tmp;
  33.           --n;
  34.         }
  35.  
  36.       return f;
  37.     }
  38. }
  39.  
  40. /**********************************************************************/
  41.  
  42. //                                                       n
  43. // via transformed matrix multiplication  of     ( 0  1 )
  44. //                                               ( 1  1 )
  45. // simplified knowing that the matrix is always of 
  46. // the form  (a b)
  47. //           (b c)
  48. // (where (a, b) and (b, c) are conseq pairs of conseq fib's;
  49. // further simplified by realizing that c = a+b, so c is only
  50. // calculated implicitly.
  51. // Given all this, do the power via the standard russian
  52. // peasant divide-and-conquer algorithm, with
  53. // the current multiplier held in (p q)
  54. //                                (q -)
  55. //
  56. // This example also shows that using procedure calls instead of operators
  57. // can be faster for Integers
  58.  
  59.  
  60. // operator version
  61.  
  62. Integer 
  63. fib2(int n) 
  64. {
  65.   ++n;                          // 1-based for compatability; see above
  66.   Integer a = 0;
  67.   if (n <= 0)
  68.     return a;
  69.   else
  70.   {
  71.     Integer b = 1;
  72.     Integer p = 0;
  73.     Integer q = 1;
  74.     
  75.     for(;;)
  76.     {
  77.       if (n == 1)
  78.         return a * p + b * q;
  79.       else if (odd (n))
  80.       {
  81.         Integer aq = a * q;
  82.         Integer bq = b * q;
  83.         a = a * p + bq;
  84.         b = b * p  + aq + bq;
  85.       }
  86.       Integer qq = q * q;
  87.       q = (q * p) * 2L + qq;
  88.       p = (p * p) + qq;
  89.       n >>= 1;
  90.     }
  91.   }
  92. }
  93.  
  94. // with all expressions named, including return value
  95.  
  96. Integer 
  97. fib2a(int n)
  98. {
  99.   Integer a = 0;
  100.   ++n;
  101.   if (n <= 0)
  102.     return a;
  103.   else
  104.   {
  105.     Integer b = 1;
  106.     Integer p = 0;
  107.     Integer q = 1;
  108.     
  109.     for(;;)
  110.     {
  111.       if (n == 1)
  112.       {
  113.         Integer bq = b * q;
  114.         a *= p ;
  115.         a += bq;
  116.     return a;
  117.       }
  118.       else if (odd (n))
  119.       {
  120.         Integer aq = a * q;
  121.         Integer bq = b * q;
  122.         a *= p;
  123.         a += bq;
  124.         b *= p;
  125.         b += bq;
  126.         b += aq;
  127.       }
  128.       Integer qq = q * q;
  129.       Integer pp = p * p;
  130.       Integer pq = p * q;
  131.       q = pq;
  132.       q += pq;
  133.       q += qq;
  134.       p = pp;
  135.       p += qq;
  136.       n >>= 1;
  137.     }
  138.   }
  139. }
  140.  
  141. // procedure call version
  142.  
  143. Integer 
  144. fib2b(int n)
  145. {
  146.   Integer a = 0;
  147.   ++n; 
  148.  
  149.   if (n <= 0)
  150.     return a;
  151.   else
  152.   {
  153.     Integer b = 1;
  154.     Integer p = 0;
  155.     Integer q = 1;
  156.     
  157.     for(;;)
  158.     {
  159.       if (n == 1)
  160.       {
  161.         Integer bq; mul(b, q, bq);
  162.         mul(a, p, a);
  163.         add(a, bq, a);
  164.     return a;
  165.       }
  166.       else if (odd (n))
  167.       {
  168.         Integer aq; mul(a, q, aq);
  169.         Integer bq; mul(b, q, bq);
  170.         mul(a, p, a);
  171.         mul(b, p, b);
  172.         add(a, bq, a);
  173.         add(b, bq, b);
  174.         add(b, aq, b);
  175.       }
  176.       Integer qq; mul(q, q, qq);
  177.       Integer pp; mul(p, p, pp);
  178.       Integer pq; mul(p, q, pq);
  179.       add(pq, pq, q);
  180.       add(q, qq, q);
  181.       add(pp, qq, p);
  182.       n >>= 1;
  183.     }
  184.   }
  185. }
  186.  
  187. // procedure call version, reusing variables
  188.  
  189. Integer 
  190. fib2c(int n)
  191. {
  192.   Integer a = 0;
  193.   ++n; 
  194.  
  195.   if (n <= 0)
  196.     return a;
  197.   else
  198.   {
  199.     Integer b = 1;
  200.     Integer p = 0;
  201.     Integer q = 1;
  202.     Integer bq, aq, qq, pp, pq;
  203.     for(;;)
  204.     {
  205.       if (n == 1)
  206.       {
  207.         mul(b, q, bq);
  208.         mul(a, p, a);
  209.         add(a, bq, a);
  210.     return a;
  211.       }
  212.       else if (odd (n))
  213.       {
  214.         mul(a, q, aq);
  215.         mul(b, q, bq);
  216.         mul(a, p, a);
  217.         mul(b, p, b);
  218.         add(a, bq, a);
  219.         add(b, bq, b);
  220.         add(b, aq, b);
  221.       }
  222.       mul(q, q, qq);
  223.       mul(p, p, pp);
  224.       mul(p, q, pq);
  225.       add(pq, pq, q);
  226.       add(q, qq, q);
  227.       add(pp, qq, p);
  228.       n >>= 1;
  229.     }
  230.   }
  231. }
  232.  
  233. /**********************************************************************/
  234. // Ullman memoizers:
  235.  
  236. class Ullman_Array
  237. {
  238.   // Ullman's array implementation allows Initialization, Store, and Fetch
  239.   // in O(1) time.  Although it takes O(n) space the time to initialize enables
  240.   // us to compute a Fibonacci number in O(log n) time!
  241.   // The basic concept of Ullman's array implementation is the use of a 
  242.   // Hand_Shake_Array and an Index_Array.  An Index location in the array is 
  243.   // only considered initialized if the contents in the Hand_Shake_Array and
  244.   // Index_Array point to each other, i.e. they ``shake hands!''
  245.   
  246. private:
  247.   int       max_array_range;
  248.   int       max_set_size;
  249.   int      *index_array;
  250.   int      *hand_shake_array;
  251.   Integer  *storage_array;
  252.   int       current_max;
  253.   
  254. public:
  255.   Integer uninitialized;
  256.  
  257.   Ullman_Array (int array_range, int set_size);
  258.   void    store (int index, Integer &item);
  259.   Integer fetch (int index);
  260.  
  261. };
  262.  
  263. inline
  264. Ullman_Array::Ullman_Array (int array_range, int set_size)
  265. {
  266.   max_array_range  = array_range;
  267.   max_set_size     = set_size;
  268.   index_array      = new int[max_array_range + 1];
  269.   hand_shake_array = new int[max_set_size];
  270.   storage_array    = new Integer[max_set_size];
  271.   current_max      = -1;
  272.   uninitialized    = 0; // No fibonacci number has value of 0.
  273. }
  274.  
  275. // Store Item at the proper Index of the Ullman array.
  276. // The Hand_Shake_Array determines whether the Index has already
  277. // been stored into.  If it has NOT, then a new location for it
  278. // is set up in the Storage_Array and the Hand_Shake_Array and Index_Array 
  279. // are set to point at each other.
  280.  
  281. inline void
  282. Ullman_Array::store (int index, Integer &item)
  283. {
  284.   int  hand_shake_index = index_array[index];
  285.   
  286.   if (hand_shake_index > current_max || hand_shake_index < 0
  287.       || index != hand_shake_array[hand_shake_index])
  288.     {
  289.       hand_shake_index                   = ++current_max;
  290.       hand_shake_array[hand_shake_index] = index;
  291.       index_array[index]                 = hand_shake_index;
  292.     }
  293.   storage_array[hand_shake_index] = item;
  294. }
  295.  
  296. // Returns uninitialized if not initialized, else returns Item at Index.
  297.  
  298. inline Integer
  299. Ullman_Array::fetch(int index) 
  300. {
  301.   int hand_shake_index = index_array[index];
  302.   
  303.   if (hand_shake_index > current_max || hand_shake_index < 0
  304.       || index != hand_shake_array[hand_shake_index])
  305.     return uninitialized;
  306.   else 
  307.     return storage_array[hand_shake_index];
  308. }
  309.  
  310. /**********************************************************************/
  311.  
  312. class Memo_Fib : public Ullman_Array
  313. {
  314. public:
  315.   Memo_Fib (int fib_num);
  316.   Integer fib3 (int n);
  317.   Integer fib3a (int n);
  318. };
  319.  
  320.  
  321. // The total number of Items computed by the Fib routine is bounded by
  322. // 4 * ceiling of log base 2 of Fib_Num.  Of course, the basis of the
  323. // recurrence is Fib(0) == 1 and Fib(1) == 1!
  324.  
  325. Memo_Fib::Memo_Fib (int fib_num) : Ullman_Array(fib_num, (4 * lg (fib_num)))
  326. {
  327.   store (0, 1);
  328.   store (1, 1);
  329. }
  330.  
  331. // Uses the memoization technique to reduce the time complexity to calculate
  332. // the nth Fibonacci number in O(log n) time.  If the value of ``n'' is
  333. // already in the table we return it in O(1) time.  Otherwise, we use the
  334. // super-nifty divide-and-conquer algorithm to break the problem up into
  335. // 4 pieces of roughly size n/2 and solve them recursively.  Although this
  336. // looks like an O(n^2) recurrence the memoization reduces the number of
  337. // recursive calls to O(log n)!
  338.  
  339. Integer
  340. Memo_Fib::fib3 (int n)
  341. {
  342.   Integer fib = fetch(n);
  343.   if (fib == uninitialized)
  344.     {
  345.       int m = n >> 1;
  346.       
  347.       fib = fib3 (m) * fib3 (n - m) + fib3 (m - 1) * fib3 (n - m - 1);
  348.       store (n, fib);
  349.     }   
  350.   return fib;
  351. }
  352.  
  353. // The same, with procedure calls instead of operators
  354.  
  355. Integer
  356. Memo_Fib::fib3a (int n)
  357. {
  358.   Integer fib = fetch(n);
  359.   if (fib == uninitialized)
  360.     {
  361.       int m = n >> 1;
  362.       Integer tmp;
  363.       mul(fib3a(m), fib3a(n - m), fib);
  364.       mul(fib3a(m - 1), fib3a(n - m - 1), tmp);
  365.       add(fib, tmp, fib);
  366.       store (n, fib);
  367.     }   
  368.   return fib;
  369. }
  370.  
  371. /**********************************************************************/
  372.  
  373. // Here's a linear-time dynamic programming solution to the same problem. 
  374. // It makes use of G++/GCC dynamic arrays to build a table of ``n'' partial 
  375. // solutions.  Naturally, there is an O(1) space solution, but this O(n) 
  376. // approach is somewhat more intuitive and follows the ``original'' recurrence
  377. // more closely.
  378.  
  379. Integer 
  380. fib4 (int n)
  381. {
  382. #ifdef __GNUC__
  383.   Integer table[n + 1];
  384. #else
  385.   Integer *table = new Integer[n + 1];
  386. #endif
  387.   table[0] = 1;
  388.   table[1] = 1;
  389.  
  390.   for (int i = 2; i <= n; i++) 
  391.     table[i] = table[i - 1] + table[i - 2];
  392.   
  393. #ifdef __GNUC__
  394.   return table[n];
  395. #else
  396.   Integer tmp = table[n];
  397.   delete [] table;
  398.   return tmp;
  399. #endif
  400. }
  401.  
  402. /**********************************************************************/
  403.  
  404. // The extended integers provide numbers of the form:
  405. // (base+sqrt(5)*Rad_5)/2^Pow_2
  406. // These are used to find the solution to the closed form of fib(n). 
  407.  
  408. struct Extended_Int
  409. {
  410.   Integer base;
  411.   Integer rad_5;
  412.   int     pow_2;
  413.  
  414.   Extended_Int (Integer ¶m1, Integer ¶m2, int param3);
  415.   Extended_Int (Extended_Int& param);
  416.   Extended_Int (void) {}
  417.  
  418.   friend Extended_Int operator- (Extended_Int ¶m1, Extended_Int ¶m2);
  419.   friend Extended_Int operator* (Extended_Int ¶m1, Extended_Int ¶m2);
  420.   friend Extended_Int sqrt (Extended_Int ¶m1);
  421.   friend Extended_Int pow  (Extended_Int ¶m1, int num);
  422. };
  423.  
  424. inline
  425. Extended_Int::Extended_Int (Integer ¶m1, Integer ¶m2, int param3)
  426. {
  427.   base  = param1;
  428.   rad_5 = param2;
  429.   pow_2 = param3;
  430. }
  431.  
  432. inline
  433. Extended_Int::Extended_Int (Extended_Int ¶m)
  434. {
  435.   base  = param.base;
  436.   rad_5 = param.rad_5;
  437.   pow_2 = param.pow_2;
  438. }
  439.  
  440. inline Extended_Int 
  441. operator- (Extended_Int ¶m1, Extended_Int ¶m2)
  442. {
  443.   Extended_Int temp;
  444.   temp.base  = param1.base - param2.base;
  445.   temp.rad_5 = param1.rad_5 - param2.rad_5;
  446.   temp.pow_2 = param1.pow_2;
  447.   return temp;
  448. }
  449.  
  450. Extended_Int 
  451. operator* (Extended_Int ¶m1, Extended_Int ¶m2)
  452. {
  453.   Extended_Int temp;
  454.   temp.base  = param1.base * param2.base + 5L * param1.rad_5 * param2.rad_5;
  455.   temp.rad_5 = param1.base * param2.rad_5 + param1.rad_5 * param2.base;
  456.   temp.pow_2 = param1.pow_2 + param2.pow_2;
  457.  
  458.   while (temp.pow_2 > 0 && !(odd (temp.base) || odd (temp.rad_5)))
  459.     {
  460.       temp.base >>= 1;
  461.       temp.rad_5 >>= 1;
  462.       temp.pow_2--;
  463.     }
  464.  
  465.   return temp;
  466. }
  467.  
  468. inline Extended_Int 
  469. sqrt (Extended_Int ¶m1)
  470. {
  471.   return param1 * param1;
  472. }
  473.  
  474. Extended_Int 
  475. pow (Extended_Int ¶m1, int num) 
  476. {
  477.   if (num > 1)
  478.     return odd (num)
  479.       ? param1 * sqrt (pow (param1, num >> 1)) : sqrt (pow (param1, num >> 1));
  480.   else 
  481.     return param1;
  482. }
  483.  
  484. /**********************************************************************/
  485.  
  486. // Calculates fib (n) by solving the closed form of the recurrence. 
  487.  
  488. class Closed_Form : private Extended_Int
  489. {
  490. private:
  491.   Extended_Int cons1;
  492.   Extended_Int cons2;
  493.  
  494. public:
  495.   Closed_Form (void): cons1 (1, 1, 1), cons2 (1, -1, 1) {}
  496.   Integer fib5 (int n);
  497. };
  498.  
  499. Integer
  500. Closed_Form::fib5 (int num) 
  501. {
  502.   Extended_Int temp = pow (cons1, num + 1) - pow (cons2, num + 1);
  503.   
  504.   while (temp.pow_2 > 0 && !(odd (temp.base) || odd (temp.rad_5)))
  505.     {
  506.       temp.base  >>= 1;
  507.       temp.rad_5 >>= 1;
  508.       temp.pow_2--;
  509.     }
  510.   
  511.   return temp.rad_5;
  512. }
  513.  
  514. /**********************************************************************/
  515.  
  516. static const int DEFAULT_SIZE = 10000;
  517.  
  518.  
  519. void dofib1(int fib_num)
  520. {
  521.   start_timer ();
  522.   Integer result = fib1 (fib_num);
  523.   double time = return_elapsed_time(0.0);
  524.   cout << "fib1 = " << result << ". Time = " << time << "\n";
  525. }
  526.  
  527. void dofib2(int fib_num)
  528. {
  529.   start_timer ();
  530.   Integer result = fib2 (fib_num);
  531.   double time = return_elapsed_time(0.0);
  532.   cout << "fib2 = " << result << ". Time = " << time << "\n";
  533. }
  534.  
  535. void dofib2a(int fib_num)
  536. {
  537.   start_timer ();
  538.   Integer result = fib2a(fib_num);
  539.   double time = return_elapsed_time(0.0);
  540.   cout << "fib2a = " << result << ". Time = " << time << "\n";
  541. }
  542.  
  543. void dofib2b(int fib_num)
  544. {
  545.   start_timer ();
  546.   Integer result = fib2b(fib_num);
  547.   double time = return_elapsed_time(0.0);
  548.   cout << "fib2b = " << result << ". Time = " << time << "\n";
  549. }
  550.  
  551. void dofib2c(int fib_num)
  552. {
  553.   start_timer ();
  554.   Integer result = fib2c(fib_num);
  555.   double time = return_elapsed_time(0.0);
  556.   cout << "fib2c = " << result << ". Time = " << time << "\n";
  557. }
  558.  
  559. void dofib3(int fib_num)
  560. {
  561.   start_timer ();
  562.   Memo_Fib    Memo_Test (fib_num);
  563.   Integer result = Memo_Test.fib3 (fib_num);
  564.   double time = return_elapsed_time(0.0);
  565.   cout << "fib3 = " << result << ". Time = " << time << "\n";
  566. }
  567.  
  568. void dofib3a(int fib_num)
  569. {
  570.   start_timer ();
  571.   Memo_Fib    Memo_Test (fib_num);
  572.   Integer result = Memo_Test.fib3a (fib_num);
  573.   double time = return_elapsed_time(0.0);
  574.   cout << "fib3a = " << result << ". Time = " << time << "\n";
  575. }
  576.  
  577. void dofib4(int fib_num)
  578. {
  579.   start_timer ();
  580.   Integer result = fib4 (fib_num);
  581.   double time = return_elapsed_time(0.0);
  582.   cout << "fib4 = " << result << ". Time = " << time << "\n";
  583. }
  584.  
  585. void dofib5(int fib_num)
  586. {
  587.   Closed_Form Rec_Test;
  588.   Integer result = Rec_Test.fib5 (fib_num);
  589.   double time = return_elapsed_time(0.0);
  590.   cout << "fib5 = " << result << ". Time = " << time << "\n";
  591. }
  592.  
  593.  
  594. int
  595. main (int argc, char *argv[])
  596. {
  597.   int         fib_num = (argc > 1) ? atoi (argv[1]) : DEFAULT_SIZE;
  598.  
  599.   cout << "Results for fib(" << fib_num << "):\n\n";
  600.  
  601.   dofib1(fib_num);
  602.   dofib2(fib_num);
  603.   dofib2a(fib_num);
  604.   dofib2b(fib_num);
  605.   dofib2c(fib_num);
  606.   dofib3(fib_num);
  607.   dofib3a(fib_num);
  608. //  dofib4(fib_num);  // This uses too much mem for large n!
  609.   dofib5(fib_num);
  610.   return 0;
  611. }
  612.  
  613.