[BACK]Return to fib_ui.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gmp / mpz

Annotation of OpenXM_contrib/gmp/mpz/fib_ui.c, Revision 1.1.1.1

1.1       maekawa     1: /* mpz_fib_ui(result, n) -- Set RESULT to the Nth Fibonacci number.
                      2:
                      3: Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
                      4:
                      5: This file is part of the GNU MP Library.
                      6:
                      7: The GNU MP Library is free software; you can redistribute it and/or modify
                      8: it under the terms of the GNU Lesser General Public License as published by
                      9: the Free Software Foundation; either version 2.1 of the License, or (at your
                     10: option) any later version.
                     11:
                     12: The GNU MP Library is distributed in the hope that it will be useful, but
                     13: WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     14: or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
                     15: License for more details.
                     16:
                     17: You should have received a copy of the GNU Lesser General Public License
                     18: along with the GNU MP Library; see the file COPYING.LIB.  If not, write to
                     19: the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
                     20: MA 02111-1307, USA. */
                     21:
                     22: #include "gmp.h"
                     23: #include "gmp-impl.h"
                     24:
                     25: /* This is fast, but could be made somewhat faster and neater.
                     26:    The timing is somewhat fluctuating for even/odd sizes because
                     27:    of the extra hair used to save variables and operations.  Here
                     28:    are a few things one might want to address:
                     29:      1. Avoid using 4 intermediate variables in mpz_fib_bigcase.
                     30:      2. Call mpn functions directly.  Straightforward for these functions.
                     31:      3. Merge the three functions into one.
                     32:
                     33: Said by Kevin:
                     34:    Consider using the Lucas numbers L[n] as an auxiliary sequence, making
                     35:    it possible to do the "doubling" operation in mpz_fib_bigcase with two
                     36:    squares rather than two multiplies.  The formulas are a little more
                     37:    complicated, something like the following (untested).
                     38:
                     39:        F[2n] = ((F[n]+L[n])^2 - 6*F[n]^2 - 4*(-1)^n) / 2
                     40:        L[2n] = 5*F[n]^2 + 2*(-1)^n
                     41:
                     42:        F[2n+1] = (F[2n] + L[2n]) / 2
                     43:        L[2n+1] = (5*F[2n] + L[2n]) / 2
                     44:
                     45:    The Lucas number that comes for free here could even be returned.
                     46:
                     47:    Maybe there's formulas with two squares using just F[n], but I don't
                     48:    know of any.
                     49: */
                     50:
                     51: /* Determine the needed storage for Fib(n).  */
                     52: #define FIB_SIZE(n) (((mp_size_t) ((n)*0.695)) / BITS_PER_MP_LIMB + 2)
                     53:
                     54: static void mpz_fib_bigcase _PROTO ((mpz_t, mpz_t, unsigned long int));
                     55: static void mpz_fib_basecase _PROTO ((mpz_t, mpz_t, unsigned long int));
                     56:
                     57:
                     58: #ifndef FIB_THRESHOLD
                     59: #define FIB_THRESHOLD 60
                     60: #endif
                     61:
                     62: void
                     63: #if __STDC__
                     64: mpz_fib_ui (mpz_t r, unsigned long int n)
                     65: #else
                     66: mpz_fib_ui (r, n)
                     67:      mpz_t r;
                     68:      unsigned long int n;
                     69: #endif
                     70: {
                     71:   if (n == 0)
                     72:     mpz_set_ui (r, 0);
                     73:   else
                     74:     {
                     75:       mpz_t t1;
                     76:       mpz_init (t1);
                     77:       if (n < FIB_THRESHOLD)
                     78:        mpz_fib_basecase (t1, r, n);
                     79:       else
                     80:        mpz_fib_bigcase (t1, r, n);
                     81:       mpz_clear (t1);
                     82:     }
                     83: }
                     84:
                     85: static void
                     86: #if __STDC__
                     87: mpz_fib_basecase (mpz_t t1, mpz_t t2, unsigned long int n)
                     88: #else
                     89: mpz_fib_basecase (t1, t2, n)
                     90:      mpz_t t1;
                     91:      mpz_t t2;
                     92:      unsigned long int n;
                     93: #endif
                     94: {
                     95:   unsigned long int m, i;
                     96:
                     97:   mpz_set_ui (t1, 0);
                     98:   mpz_set_ui (t2, 1);
                     99:   m = n/2;
                    100:   for (i = 0; i < m; i++)
                    101:     {
                    102:       mpz_add (t1, t1, t2);
                    103:       mpz_add (t2, t1, t2);
                    104:     }
                    105:   if ((n & 1) == 0)
                    106:     {
                    107:       mpz_sub (t1, t2, t1);
                    108:       mpz_sub (t2, t2, t1);    /* trick: recover t1 value just overwritten */
                    109:     }
                    110: }
                    111:
                    112: static void
                    113: #if __STDC__
                    114: mpz_fib_bigcase (mpz_t t1, mpz_t t2, unsigned long int n)
                    115: #else
                    116: mpz_fib_bigcase (t1, t2, n)
                    117:      mpz_t t1;
                    118:      mpz_t t2;
                    119:      unsigned long int n;
                    120: #endif
                    121: {
                    122:   unsigned long int n2;
                    123:   int ni, i;
                    124:   mpz_t x1, x2, u1, u2;
                    125:
                    126:   ni = 0;
                    127:   for (n2 = n; n2 >= FIB_THRESHOLD; n2 /= 2)
                    128:     ni++;
                    129:
                    130:   mpz_fib_basecase (t1, t2, n2);
                    131:
                    132:   mpz_init (x1);
                    133:   mpz_init (x2);
                    134:   mpz_init (u1);
                    135:   mpz_init (u2);
                    136:
                    137:   for (i = ni - 1; i >= 0; i--)
                    138:     {
                    139:       mpz_mul_2exp (x1, t1, 1);
                    140:       mpz_mul_2exp (x2, t2, 1);
                    141:
                    142:       mpz_add (x1, x1, t2);
                    143:       mpz_sub (x2, x2, t1);
                    144:
                    145:       mpz_mul (u1, t2, x1);
                    146:       mpz_mul (u2, t1, x2);
                    147:
                    148:       if (((n >> i) & 1) == 0)
                    149:        {
                    150:          mpz_sub (t1, u1, u2);
                    151:          mpz_set (t2, u1);
                    152:        }
                    153:       else
                    154:        {
                    155:          mpz_set (t1, u1);
                    156:          mpz_mul_2exp (t2, u1, 1);
                    157:          mpz_sub (t2, t2, u2);
                    158:        }
                    159:     }
                    160:
                    161:   mpz_clear (x1);
                    162:   mpz_clear (x2);
                    163:   mpz_clear (u1);
                    164:   mpz_clear (u2);
                    165: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>