chiark / gitweb /
@@@ more mess
[mLib] / test / example / fib.c
1 /* -*-c-*-
2  *
3  * Compute elements of the Fibonacci sequence
4  *
5  * (c) 2024 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of the mLib utilities library.
11  *
12  * mLib is free software: you can redistribute it and/or modify it under
13  * the terms of the GNU Library General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or (at
15  * your option) any later version.
16  *
17  * mLib is distributed in the hope that it will be useful, but WITHOUT
18  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
20  * License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public
23  * License along with mLib.  If not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
25  * USA.
26  */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 #include "example.h"
31
32 /*----- Main code ---------------------------------------------------------*/
33
34 unsigned long recfib(unsigned n)
35   { return (n <= 1 ? n : recfib(n - 1) + recfib(n - 2)); }
36
37 unsigned long iterfib(unsigned n)
38 {
39   unsigned long u, v, t;
40
41   for (u = 0, v = 1; n--; t = v, v = u, u += t);
42   return (u);
43 }
44
45 unsigned long expfib(unsigned n)
46 {
47   unsigned long a, b, u, v, t;
48
49   /* We work in %$\Q(\phi)$%, where %$\phi^2 = \phi + 1$%.  I claim that
50    * %$\phi^k = F_k \phi + F_{k-1} \pmod f(\phi))$%.  Proof by induction:
51    * note that * %$F_{-1} = F_1 - F_0 = 1$%, so %$\phi^0 = 1 = {}$%
52    * %$F_0 \phi + F_{-1}$%; and %$\phi^{k+1} = F_k \phi^2 + {}$%
53    * %$F_{k-1} \phi = F_k (\phi + 1) + F_{k-1} \phi = (F_k + {}$%
54    * %$F_{k-1} \phi + F_k = F_{k+1} \phi + F_k$% as claimed.
55    *
56    * Now, notice that %$(a \phi + b) (c \phi + d) = a c \phi^2 + {}$%
57    * $%(a d + b c) \phi + b d = a c (\phi + 1) + (a d + b c) \phi + {}$%
58    * %$b d = (a c + a d + b c) \phi + (a c + b d)$%.  In particular,
59    * %$(u \phi + v)^2 \equiv (u^2 + 2 u v) \phi + (u^2 + v^2)$%.
60    */
61   a = 0, b = 1; u = 1, v = 0;
62   if (n)
63     for (;;) {
64       if (n%2) { t = a*u; a = t + a*v + b*u; b = t + b*v; }
65       n /= 2; if (!n) break;
66       t = u*u; u = t + 2*u*v; v = t + v*v;
67     }
68   return (a);
69 }
70
71 /*----- That's all, folks -------------------------------------------------*/