File: fibonacci.cc

package info (click to toggle)
cln 1.3.1-2
  • links: PTS
  • area: main
  • in suites: squeeze
  • size: 11,056 kB
  • ctags: 16,803
  • sloc: cpp: 81,043; sh: 10,611; ansic: 3,281; makefile: 1,302
file content (171 lines) | stat: -rw-r--r-- 4,237 bytes parent folder | download | duplicates (8)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
// Compute and print the n-th Fibonacci number.

// We work with integers and real numbers.
#include <cln/integer.h>
#include <cln/real.h>

// We do I/O.
#include <cln/io.h>
#include <cln/integer_io.h>

// We use the timing functions.
#include <cln/timing.h>

using namespace std;
using namespace cln;

// F_n is defined through the recurrence relation
//      F_0 = 0, F_1 = 1, F_(n+2) = F_(n+1) + F_n.
// The following addition formula holds:
//      F_(n+m)   = F_(m-1) * F_n + F_m * F_(n+1)  for m >= 1, n >= 0.
// (Proof: For fixed m, the LHS and the RHS satisfy the same recurrence
// w.r.t. n, and the initial values (n=0, n=1) agree. Hence all values agree.)
// Replace m by m+1:
//      F_(n+m+1) = F_m * F_n + F_(m+1) * F_(n+1)      for m >= 0, n >= 0
// Now put in m = n, to get
//      F_(2n) = (F_(n+1)-F_n) * F_n + F_n * F_(n+1) = F_n * (2*F_(n+1) - F_n)
//      F_(2n+1) = F_n ^ 2 + F_(n+1) ^ 2
// hence
//      F_(2n+2) = F_(n+1) * (2*F_n + F_(n+1))

struct twofibs {
	cl_I u; // F_n
	cl_I v; // F_(n+1)
	// Constructor.
	twofibs (const cl_I& uu, const cl_I& vv) : u (uu), v (vv) {}
};

// Returns F_n and F_(n+1). Assume n>=0.
static const twofibs fibonacci2 (int n)
{
	if (n==0)
		return twofibs(0,1);
	int m = n/2; // floor(n/2)
	twofibs Fm = fibonacci2(m);
	// Since a squaring is cheaper than a multiplication, better use
	// three squarings instead of one multiplication and two squarings.
	cl_I u2 = square(Fm.u);
	cl_I v2 = square(Fm.v);
	if (n==2*m) {
		// n = 2*m
		cl_I uv2 = square(Fm.v - Fm.u);
		return twofibs(v2 - uv2, u2 + v2);
	} else {
		// n = 2*m+1
		cl_I uv2 = square(Fm.u + Fm.v);
		return twofibs(u2 + v2, uv2 - u2);
	}
}

// Returns just F_n. Assume n>=0.
const cl_I fibonacci (int n)
{
	if (n==0)
		return 0;
	int m = n/2; // floor(n/2)
	twofibs Fm = fibonacci2(m);
	if (n==2*m) {
		// n = 2*m
		// Here we don't use the squaring formula because
		// one multiplication is cheaper than two squarings.
		cl_I& u = Fm.u;
		cl_I& v = Fm.v;
		return u * ((v << 1) - u);
	} else {
		// n = 2*m+1
		cl_I u2 = square(Fm.u);
		cl_I v2 = square(Fm.v);
		return u2 + v2;
	}
}

// The next routine is a variation of the above.  It is mathematically
// equivalent but implemented in a non-recursive way.
const cl_I fibonacci_compact (int n)
{
	if (n==0)
		return 0;
	cl_I u = 0;
	cl_I v = 1;
	cl_I m = n/2; // floor(n/2)
	for (uintC bit=integer_length(m); bit>0; --bit) {
		// Since a squaring is cheaper than a multiplication, better use
		// three squarings instead of one multiplication and two squarings.
		cl_I u2 = square(u);
		cl_I v2 = square(v);
		if (logbitp(bit-1, m)) {
			v = square(u + v) - u2;
			u = u2 + v2;
		} else {
			u = v2 - square(v - u);
			v = u2 + v2;
		}
	}
	if (n==2*m)
		// Here we don't use the squaring formula because
		// one multiplication is cheaper than two squarings.
		return u * ((v << 1) - u);
	else
		return square(u) + square(v);
}

// Returns just F_n, computed as the nearest integer to
// ((1+sqrt(5))/2)^n/sqrt(5). Assume n>=0.
const cl_I fibonacci_slow (int n)
{
	// Need a precision of ((1+sqrt(5))/2)^-n.
	float_format_t prec = float_format((int)(0.208987641*n+5));
	cl_R sqrt5 = sqrt(cl_float(5,prec));
	cl_R phi = (1+sqrt5)/2;
	return round1( expt(phi,n)/sqrt5 );
}

#ifndef TIMING

int main (int argc, char* argv[])
{
	if (argc != 2) {
		cerr << "Usage: fibonacci n" << endl;
		return(1);
	}
	int n = atoi(argv[1]);
	cout << "fib(" << n << ") = " << fibonacci(n) << endl;
	return(0);
}

#else // TIMING

int main (int argc, char* argv[])
{
	int repetitions = 100;
	if ((argc >= 3) && !strcmp(argv[1],"-r")) {
		repetitions = atoi(argv[2]);
		argc -= 2; argv += 2;
	}
	if (argc != 2) {
		cerr << "Usage: fibonacci n" << endl;
		return(1);
	}
	int n = atoi(argv[1]);
	{ CL_TIMING;
		cout << "fib(" << n << ") = ";
		for (int rep = repetitions-1; rep > 0; rep--)
			fibonacci(n);
		cout << fibonacci(n) << endl;
	}
	{ CL_TIMING;
		cout << "fib(" << n << ") = ";
		for (int rep = repetitions-1; rep > 0; rep--)
			fibonacci_compact(n);
		cout << fibonacci_compact(n) << endl;
	}
	{ CL_TIMING;
		cout << "fib(" << n << ") = ";
		for (int rep = repetitions-1; rep > 0; rep--)
			fibonacci_slow(n);
		cout << fibonacci_slow(n) << endl;
	}
	return(0);
}

#endif