|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T f
Length: 9968 (0x26f0)
Types: TextFile
Names: »fib.cc«
└─⟦a05ed705a⟧ Bits:30007078 DKUUG GNU 2/12/89
└─⟦cc8755de2⟧ »./libg++-1.36.1.tar.Z«
└─⟦23757c458⟧
└─⟦this⟧ »libg++/etc/fib.cc«
#include <stream.h>
#include <Integer.h>
// Fun and games with the Fibonacci function.
// Also demonstrates use of the `named return value' extension.
// fib1 and fib2 from Doug Lea, others from Doug Schmidt.
/**********************************************************************/
// Standard iterative version:
// Schmidt uses convention that fib(0) = 1, not fib(0) = 0;
// so I just increment n here.
Integer
fib1(int n)
{
++n;
if (n <= 0)
return 0;
else
{
Integer f = 1;
Integer prev = 0;
while (n > 1)
{
Integer tmp = f;
f += prev;
prev = tmp;
--n;
}
return f;
}
}
/**********************************************************************/
// n
// via transformed matrix multiplication of ( 0 1 )
// ( 1 1 )
// simplified knowing that the matrix is always of
// the form (a b)
// (b c)
// (where (a, b) and (b, c) are conseq pairs of conseq fib's;
// further simplified by realizing that c = a+b, so c is only
// calculated implicitly.
// Given all this, do the power via the standard russian
// peasant divide-and-conquer algorithm, with
// the current multiplier held in (p q)
// (q -)
//
// This example also shows that using op= instead of op is often
// faster for Integers
Integer
fib2(int n)
{
++n; // 1-based for compatability; see above
Integer a = 0;
if (n <= 0)
return a;
else
{
Integer b = 1;
Integer p = 0;
Integer q = 1;
Integer temp, temp2;
for(;;)
{
if (n == 1)
{
a *= p;
b *= q;
a += b;
return a;
}
else if (odd (n))
{
temp = q;
temp2 = q;
temp *= b;
temp2 *= a;
b *= p;
b += temp2;
b += temp;
a *= p;
a += temp;
}
temp = q;
temp *= q;
q *= p;
q += q;
q += temp;
p *= p;
p += temp;
n >>= 1;
}
}
}
/**********************************************************************/
// Ullman memoizers:
class Ullman_Array
{
// Ullman's array implementation allows Initialization, Store, and Fetch
// in O(1) time. Although it takes O(n) space the time to initialize enables
// us to compute a Fibonacci number in O(log n) time!
// The basic concept of Ullman's array implementation is the use of a
// Hand_Shake_Array and an Index_Array. An Index location in the array is
// only considered initialized if the contents in the Hand_Shake_Array and
// Index_Array point to each other, i.e. they ``shake hands!''
private:
int max_array_range;
int max_set_size;
int *index_array;
int *hand_shake_array;
Integer *storage_array;
int current_max;
public:
Integer uninitialized;
Ullman_Array (int array_range, int set_size);
void store (int index, Integer &item);
Integer fetch (int index);
};
inline
Ullman_Array::Ullman_Array (int array_range, int set_size)
{
max_array_range = array_range;
max_set_size = set_size;
index_array = new int[max_array_range + 1];
hand_shake_array = new int[max_set_size];
storage_array = new Integer[max_set_size];
current_max = -1;
uninitialized = 0; // No fibonacci number has value of 0.
}
// Store Item at the proper Index of the Ullman array.
// The Hand_Shake_Array determines whether the Index has already
// been stored into. If it has NOT, then a new location for it
// is set up in the Storage_Array and the Hand_Shake_Array and Index_Array
// are set to point at each other.
inline void
Ullman_Array::store (int index, Integer &item)
{
int hand_shake_index = index_array[index];
if (hand_shake_index > current_max || hand_shake_index < 0
|| index != hand_shake_array[hand_shake_index])
{
hand_shake_index = ++current_max;
hand_shake_array[hand_shake_index] = index;
index_array[index] = hand_shake_index;
}
storage_array[hand_shake_index] = item;
}
// Returns uninitialized if not initialized, else returns Item at Index.
inline Integer
Ullman_Array::fetch(int index)
{
int hand_shake_index = index_array[index];
if (hand_shake_index > current_max || hand_shake_index < 0
|| index != hand_shake_array[hand_shake_index])
return uninitialized;
else
return storage_array[hand_shake_index];
}
/**********************************************************************/
class Memo_Fib : public Ullman_Array
{
public:
Memo_Fib (int fib_num);
Integer fib3 (int n);
};
// The total number of Items computed by the Fib routine is bounded by
// 4 * ceiling of log base 2 of Fib_Num. Of course, the basis of the
// recurrence is Fib(0) == 1 and Fib(1) == 1!
Memo_Fib::Memo_Fib (int fib_num): (fib_num, (4 * lg (fib_num)))
{
store (0, 1);
store (1, 1);
}
// Uses the memoization technique to reduce the time complexity to calculate
// the nth Fibonacci number in O(log n) time. If the value of ``n'' is
// already in the table we return it in O(1) time. Otherwise, we use the
// super-nifty divide-and-conquer algorithm to break the problem up into
// 4 pieces of roughly size n/2 and solve them recursively. Although this
// looks like an O(n^2) recurrence the memoization reduces the number of
// recursive calls to O(log n)!
Integer
Memo_Fib::fib3 (int n) return fib (fetch (n));
{
if (fib == uninitialized)
{
int m = n >> 1;
fib = fib3 (m) * fib3 (n - m) + fib3 (m - 1) * fib3 (n - m - 1);
store (n, fib);
}
}
/**********************************************************************/
// Here's a linear-time dynamic programming solution to the same problem.
// It makes use of G++/GCC dynamic arrays to build a table of ``n'' partial
// solutions. Naturally, there is an O(1) space solution, but this O(n)
// approach is somewhat more intuitive and follows the ``original'' recurrence
// more closely.
Integer
fib4 (int n)
{
Integer table[n + 1];
table[0] = 1;
table[1] = 1;
for (int i = 2; i <= n; i++)
table[i] = table[i - 1] + table[i - 2];
return table[n];
}
/**********************************************************************/
// The extended integers provide numbers of the form:
// (base+sqrt(5)*Rad_5)/2^Pow_2
// These are used to find the solution to the closed form of fib(n).
struct Extended_Int
{
Integer base;
Integer rad_5;
int pow_2;
Extended_Int (Integer ¶m1, Integer ¶m2, int param3);
Extended_Int (Extended_Int& param);
Extended_Int (void) {}
friend Extended_Int operator- (Extended_Int ¶m1, Extended_Int ¶m2);
friend Extended_Int operator* (Extended_Int ¶m1, Extended_Int ¶m2);
friend Extended_Int sqrt (Extended_Int ¶m1);
friend Extended_Int pow (Extended_Int ¶m1, int num);
};
inline
Extended_Int::Extended_Int (Integer ¶m1, Integer ¶m2, int param3)
{
base = param1;
rad_5 = param2;
pow_2 = param3;
}
inline
Extended_Int::Extended_Int (Extended_Int ¶m)
{
base = param.base;
rad_5 = param.rad_5;
pow_2 = param.pow_2;
}
inline Extended_Int
operator- (Extended_Int ¶m1, Extended_Int ¶m2) return temp;
{
temp.base = param1.base - param2.base;
temp.rad_5 = param1.rad_5 - param2.rad_5;
temp.pow_2 = param1.pow_2;
}
Extended_Int
operator* (Extended_Int ¶m1, Extended_Int ¶m2) return temp;
{
temp.base = param1.base * param2.base + 5 * param1.rad_5 * param2.rad_5;
temp.rad_5 = param1.base * param2.rad_5 + param1.rad_5 * param2.base;
temp.pow_2 = param1.pow_2 + param2.pow_2;
while (temp.pow_2 > 0 && !(odd (temp.base) || odd (temp.rad_5)))
{
temp.base >>= 1;
temp.rad_5 >>= 1;
temp.pow_2--;
}
}
inline Extended_Int
sqrt (Extended_Int ¶m1)
{
return param1 * param1;
}
Extended_Int
pow (Extended_Int ¶m1, int num)
{
if (num > 1)
return odd (num)
? param1 * sqrt (pow (param1, num >> 1)) : sqrt (pow (param1, num >> 1));
else
return param1;
}
/**********************************************************************/
// Calculates fib (n) by solving the closed form of the recurrence.
class Closed_Form : private Extended_Int
{
private:
Extended_Int cons1;
Extended_Int cons2;
public:
Closed_Form (void): cons1 (1, 1, 1), cons2 (1, -1, 1) {}
Integer fib5 (int n);
};
Integer
Closed_Form::fib5 (int num)
{
Extended_Int temp = pow (cons1, num + 1) - pow (cons2, num + 1);
while (temp.pow_2 > 0 && !(odd (temp.base) || odd (temp.rad_5)))
{
temp.base >>= 1;
temp.rad_5 >>= 1;
temp.pow_2--;
}
return temp.rad_5;
}
/**********************************************************************/
static const int DEFAULT_SIZE = 10000;
int
main (int argc, char *argv[])
{
int fib_num = (argc > 1) ? atoi (argv[1]) : DEFAULT_SIZE;
Memo_Fib Memo_Test (fib_num);
Closed_Form Rec_Test;
Integer result;
double ftime;
cout << "Results for fib(" << fib_num << "):\n\n";
start_timer ();
result = fib1 (fib_num);
ftime = return_elapsed_time (0.0);
cout << "fib1 = " << result << ". Time = " << ftime << "\n";
start_timer ();
result = fib2 (fib_num);
ftime = return_elapsed_time (0.0);
cout << "fib2 = " << result << ". Time = " << ftime << "\n";
start_timer ();
result = Memo_Test.fib3 (fib_num);
ftime = return_elapsed_time (0.0);
cout << "fib3 = " << result << ". Time = " << ftime << "\n";
start_timer ();
result = fib4 (fib_num);
ftime = return_elapsed_time (0.0);
cout << "fib4 = " << result << ". Time = " << ftime << "\n";
start_timer ();
result = Rec_Test.fib5 (fib_num);
ftime = return_elapsed_time (0.0);
cout << "fib5 = " << result << ". Time = " << ftime << "\n";
return 0;
}