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
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							143 lines
						
					
					
						
							3.4 KiB
						
					
					
				| // Compute and print the n-th Fibonacci number. | |
|  | |
| // We work with integers and real numbers. | |
| #include <cl_integer.h> | |
| #include <cl_real.h> | |
|  | |
| // We do I/O. | |
| #include <cl_io.h> | |
| #include <cl_integer_io.h> | |
|  | |
| // We use the timing functions. | |
| #include <cl_timing.h> | |
|  | |
| // Declare the exit() function. | |
| #include <stdlib.h> | |
|  | |
| // 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; | |
| 	} | |
| } | |
| 
 | |
| // 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. | |
| 	cl_float_format_t prec = cl_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) { | |
| 		fprint(cl_stderr, "Usage: fibonacci n\n"); | |
| 		exit(1); | |
| 	} | |
| 	int n = atoi(argv[1]); | |
| 	fprint(cl_stdout, "fib("); | |
| 	fprintdecimal(cl_stdout, n); | |
| 	fprint(cl_stdout, ") = "); | |
| 	fprint(cl_stdout, fibonacci(n)); | |
| 	fprint(cl_stdout, "\n"); | |
| } | |
| 
 | |
| #else // TIMING | |
|  | |
| int main (int argc, char* argv[]) | |
| { | |
| 	int repetitions = 1; | |
| 	if ((argc >= 3) && !strcmp(argv[1],"-r")) { | |
| 		repetitions = atoi(argv[2]); | |
| 		argc -= 2; argv += 2; | |
| 	} | |
| 	if (argc != 2) { | |
| 		fprint(cl_stderr, "Usage: fibonacci n\n"); | |
| 		exit(1); | |
| 	} | |
| 	int n = atoi(argv[1]); | |
| 	{ CL_TIMING; | |
| 		fprint(cl_stdout, "fib("); | |
| 		fprintdecimal(cl_stdout, n); | |
| 		fprint(cl_stdout, ") = "); | |
| 		for (int rep = repetitions-1; rep > 0; rep--) | |
| 			fibonacci(n); | |
| 		fprint(cl_stdout, fibonacci(n)); | |
| 		fprint(cl_stdout, "\n"); | |
| 	} | |
| 	{ CL_TIMING; | |
| 		fprint(cl_stdout, "fib("); | |
| 		fprintdecimal(cl_stdout, n); | |
| 		fprint(cl_stdout, ") = "); | |
| 		for (int rep = repetitions-1; rep > 0; rep--) | |
| 			fibonacci_slow(n); | |
| 		fprint(cl_stdout, fibonacci_slow(n)); | |
| 		fprint(cl_stdout, "\n"); | |
| 	} | |
| } | |
| 
 | |
| #endif
 |