Annotation of OpenXM_contrib/gmp/mpz/fib_ui.c, Revision 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>