matrix and fibonacci

Timon Gehr timon.gehr at gmx.ch
Sat Mar 10 14:28:56 PST 2012


On 03/10/2012 11:00 PM, newcomer[bob] wrote:
> On Friday, 9 March 2012 at 14:07:10 UTC, Timon Gehr wrote:
>> On 03/09/2012 06:50 AM, newcomer[bob] wrote:
>>> The following is a matrix implementation of the fibonacci algorithm:
>>>
>>> int fib(int n) { int M[2][2] = {{1,0},{0,1}} for (int i = 1; i < n;
>>> i++) M = M * {{1,1},{1,0}} return M[0][0]; }
>>>
>>> problem is I don't really understand how matrix multiplication works
>>> so i cannot translate it to an equivalent solution in D. Thank for
>>> you assistance in advance.
>>>
>>> newcomer[bob]
>>
>
> Thanks very much for the assist. All three of these methods
> though, seem to have a bug.

I just start the sequence from 1, because a quick glance at your 
implementation showed that it starts from 1. But it seems like actually 
it would produce the sequence 1,1,1,2,3,...

> fib(), fi() and f() all produce the
> same incorrect result which for lack of better word I'll call an
> "off by one" bug. A call to any of these functions with any
> integer value between 2 and 44 yields the return value of the
> next higher integer, while 45 overflows.

I don't observe any overflowing. But the assertions are a little too 
tight, 46 would be the first one that does not work.

> For example, 2 => 2, 10
> => 89, and 15 => 987 which are the actual values for 3, 11 and 16.
>
> Thanks,
> Bob
>

Probably this is what you want then:

// simple 2x2 matrix type
alias int[2][2] Mat;
// 2x2 matrix multiplication
Mat matmul(Mat a, Mat b){
	return [[a[0][0]*b[0][0]+a[0][1]*b[1][0], a[0][0]*b[0][1]+a[0][1]*b[1][1]],
	        [a[1][0]*b[0][0]+a[1][1]*b[1][0], 
a[0][1]*b[0][1]+a[1][1]*b[1][1]]];
}
// implementation of your algorithm
int fib(int n)in{assert(n>=0 && n<47);}body{
	if(!n) return 0;
	int M[2][2] = [[1,0],[0,1]];
	int F[2][2] = [[1,1],[1,0]];
	foreach (i; 1..n) M = matmul(F,M);
	return M[0][0];
  }
// faster way of computing matrix power
int fi(int n)in{assert(n>=0 && n<47);}body{
	if(!n) return 0;
	Mat M = [[1,0],[0,1]];
	Mat F = [[1,1],[1,0]];
	for(n--;n;n>>=1){
		if(n&1) M = matmul(F,M);
		F = matmul(F,F);
	}
	return M[0][0];
  }
// closed form derived from basis transform to eigenbasis
int f(int n)in{assert(n>=0 && n<47);}body{
	enum sqrt5=sqrt(5.0);
	return cast(int)((((1+sqrt5)/2)^^n-((1-sqrt5)/2)^^n)/sqrt5);
}


More information about the Digitalmars-d-learn mailing list