[BACK]Return to fib2_ui.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gmp / mpn / generic

Annotation of OpenXM_contrib/gmp/mpn/generic/fib2_ui.c, Revision 1.1

1.1     ! ohara       1: /* mpn_fib2_ui -- calculate Fibonacci numbers.
        !             2:
        !             3: Copyright 2001, 2002 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 <stdio.h>
        !            23: #include "gmp.h"
        !            24: #include "gmp-impl.h"
        !            25: #include "longlong.h"
        !            26:
        !            27:
        !            28: /* change this to "#define TRACE(x) x" for diagnostics */
        !            29: #define TRACE(x)
        !            30:
        !            31:
        !            32: /* The following table was generated by code at the end of this file. */
        !            33:
        !            34: const mp_limb_t
        !            35: __gmp_fib_table[FIB_TABLE_LIMIT+2] = {
        !            36:
        !            37: #if GMP_NUMB_BITS >= 4
        !            38:   CNST_LIMB (0x1),  /* -1 */
        !            39:   CNST_LIMB (0x0),  /* 0 */
        !            40:   CNST_LIMB (0x1),  /* 1 */
        !            41:   CNST_LIMB (0x1),  /* 2 */
        !            42:   CNST_LIMB (0x2),  /* 3 */
        !            43:   CNST_LIMB (0x3),  /* 4 */
        !            44:   CNST_LIMB (0x5),  /* 5 */
        !            45:   CNST_LIMB (0x8),  /* 6 */
        !            46:   CNST_LIMB (0xD),  /* 7 */
        !            47: #endif
        !            48: #if GMP_NUMB_BITS >= 8
        !            49:   CNST_LIMB (0x15),  /* 8 */
        !            50:   CNST_LIMB (0x22),  /* 9 */
        !            51:   CNST_LIMB (0x37),  /* 10 */
        !            52:   CNST_LIMB (0x59),  /* 11 */
        !            53:   CNST_LIMB (0x90),  /* 12 */
        !            54:   CNST_LIMB (0xE9),  /* 13 */
        !            55: #endif
        !            56: #if GMP_NUMB_BITS >= 16
        !            57:   CNST_LIMB (0x179),  /* 14 */
        !            58:   CNST_LIMB (0x262),  /* 15 */
        !            59:   CNST_LIMB (0x3DB),  /* 16 */
        !            60:   CNST_LIMB (0x63D),  /* 17 */
        !            61:   CNST_LIMB (0xA18),  /* 18 */
        !            62:   CNST_LIMB (0x1055),  /* 19 */
        !            63:   CNST_LIMB (0x1A6D),  /* 20 */
        !            64:   CNST_LIMB (0x2AC2),  /* 21 */
        !            65:   CNST_LIMB (0x452F),  /* 22 */
        !            66:   CNST_LIMB (0x6FF1),  /* 23 */
        !            67:   CNST_LIMB (0xB520),  /* 24 */
        !            68: #endif
        !            69: #if GMP_NUMB_BITS >= 32
        !            70:   CNST_LIMB (0x12511),  /* 25 */
        !            71:   CNST_LIMB (0x1DA31),  /* 26 */
        !            72:   CNST_LIMB (0x2FF42),  /* 27 */
        !            73:   CNST_LIMB (0x4D973),  /* 28 */
        !            74:   CNST_LIMB (0x7D8B5),  /* 29 */
        !            75:   CNST_LIMB (0xCB228),  /* 30 */
        !            76:   CNST_LIMB (0x148ADD),  /* 31 */
        !            77:   CNST_LIMB (0x213D05),  /* 32 */
        !            78:   CNST_LIMB (0x35C7E2),  /* 33 */
        !            79:   CNST_LIMB (0x5704E7),  /* 34 */
        !            80:   CNST_LIMB (0x8CCCC9),  /* 35 */
        !            81:   CNST_LIMB (0xE3D1B0),  /* 36 */
        !            82:   CNST_LIMB (0x1709E79),  /* 37 */
        !            83:   CNST_LIMB (0x2547029),  /* 38 */
        !            84:   CNST_LIMB (0x3C50EA2),  /* 39 */
        !            85:   CNST_LIMB (0x6197ECB),  /* 40 */
        !            86:   CNST_LIMB (0x9DE8D6D),  /* 41 */
        !            87:   CNST_LIMB (0xFF80C38),  /* 42 */
        !            88:   CNST_LIMB (0x19D699A5),  /* 43 */
        !            89:   CNST_LIMB (0x29CEA5DD),  /* 44 */
        !            90:   CNST_LIMB (0x43A53F82),  /* 45 */
        !            91:   CNST_LIMB (0x6D73E55F),  /* 46 */
        !            92:   CNST_LIMB (0xB11924E1),  /* 47 */
        !            93: #endif
        !            94: #if GMP_NUMB_BITS >= 64
        !            95:   CNST_LIMB (0x11E8D0A40),  /* 48 */
        !            96:   CNST_LIMB (0x1CFA62F21),  /* 49 */
        !            97:   CNST_LIMB (0x2EE333961),  /* 50 */
        !            98:   CNST_LIMB (0x4BDD96882),  /* 51 */
        !            99:   CNST_LIMB (0x7AC0CA1E3),  /* 52 */
        !           100:   CNST_LIMB (0xC69E60A65),  /* 53 */
        !           101:   CNST_LIMB (0x1415F2AC48),  /* 54 */
        !           102:   CNST_LIMB (0x207FD8B6AD),  /* 55 */
        !           103:   CNST_LIMB (0x3495CB62F5),  /* 56 */
        !           104:   CNST_LIMB (0x5515A419A2),  /* 57 */
        !           105:   CNST_LIMB (0x89AB6F7C97),  /* 58 */
        !           106:   CNST_LIMB (0xDEC1139639),  /* 59 */
        !           107:   CNST_LIMB (0x1686C8312D0),  /* 60 */
        !           108:   CNST_LIMB (0x2472D96A909),  /* 61 */
        !           109:   CNST_LIMB (0x3AF9A19BBD9),  /* 62 */
        !           110:   CNST_LIMB (0x5F6C7B064E2),  /* 63 */
        !           111:   CNST_LIMB (0x9A661CA20BB),  /* 64 */
        !           112:   CNST_LIMB (0xF9D297A859D),  /* 65 */
        !           113:   CNST_LIMB (0x19438B44A658),  /* 66 */
        !           114:   CNST_LIMB (0x28E0B4BF2BF5),  /* 67 */
        !           115:   CNST_LIMB (0x42244003D24D),  /* 68 */
        !           116:   CNST_LIMB (0x6B04F4C2FE42),  /* 69 */
        !           117:   CNST_LIMB (0xAD2934C6D08F),  /* 70 */
        !           118:   CNST_LIMB (0x1182E2989CED1),  /* 71 */
        !           119:   CNST_LIMB (0x1C5575E509F60),  /* 72 */
        !           120:   CNST_LIMB (0x2DD8587DA6E31),  /* 73 */
        !           121:   CNST_LIMB (0x4A2DCE62B0D91),  /* 74 */
        !           122:   CNST_LIMB (0x780626E057BC2),  /* 75 */
        !           123:   CNST_LIMB (0xC233F54308953),  /* 76 */
        !           124:   CNST_LIMB (0x13A3A1C2360515),  /* 77 */
        !           125:   CNST_LIMB (0x1FC6E116668E68),  /* 78 */
        !           126:   CNST_LIMB (0x336A82D89C937D),  /* 79 */
        !           127:   CNST_LIMB (0x533163EF0321E5),  /* 80 */
        !           128:   CNST_LIMB (0x869BE6C79FB562),  /* 81 */
        !           129:   CNST_LIMB (0xD9CD4AB6A2D747),  /* 82 */
        !           130:   CNST_LIMB (0x16069317E428CA9),  /* 83 */
        !           131:   CNST_LIMB (0x23A367C34E563F0),  /* 84 */
        !           132:   CNST_LIMB (0x39A9FADB327F099),  /* 85 */
        !           133:   CNST_LIMB (0x5D4D629E80D5489),  /* 86 */
        !           134:   CNST_LIMB (0x96F75D79B354522),  /* 87 */
        !           135:   CNST_LIMB (0xF444C01834299AB),  /* 88 */
        !           136:   CNST_LIMB (0x18B3C1D91E77DECD),  /* 89 */
        !           137:   CNST_LIMB (0x27F80DDAA1BA7878),  /* 90 */
        !           138:   CNST_LIMB (0x40ABCFB3C0325745),  /* 91 */
        !           139:   CNST_LIMB (0x68A3DD8E61ECCFBD),  /* 92 */
        !           140:   CNST_LIMB (0xA94FAD42221F2702),  /* 93 */
        !           141: #endif
        !           142: };
        !           143:
        !           144:
        !           145: /* Store F[n] at fp and F[n-1] at f1p.  fp and f1p should have room for
        !           146:    MPN_FIB2_SIZE(n) limbs.
        !           147:
        !           148:    The return value is the actual number of limbs stored, this will be at
        !           149:    least 1.  fp[size-1] will be non-zero, except when n==0, in which case
        !           150:    fp[0] is 0 and f1p[0] is 1.  f1p[size-1] can be zero, since F[n-1]<F[n]
        !           151:    (for n>0).
        !           152:
        !           153:    Notes:
        !           154:
        !           155:    In F[2k+1] with k even, +2 is applied to 4*F[k]^2 just by ORing into the
        !           156:    low limb.
        !           157:
        !           158:    In F[2k+1] with k odd, -2 is applied to the low limb of 4*F[k]^2 -
        !           159:    F[k-1]^2.  This F[2k+1] is an F[4m+3] and such numbers are congruent to
        !           160:    1, 2 or 5 mod 8, which means no underflow reaching it with a -2 (since
        !           161:    that would leave 6 or 7 mod 8).
        !           162:
        !           163:    This property of F[4m+3] can be verified by induction on F[4m+3] =
        !           164:    7*F[4m-1] - F[4m-5], that formula being a standard lucas sequence
        !           165:    identity U[i+j] = U[i]*V[j] - U[i-j]*Q^j.
        !           166:
        !           167:    Enhancements:
        !           168:
        !           169:    If there was an mpn_addlshift, it'd be possible to eliminate the yp
        !           170:    temporary, using xp=F[k]^2, fp=F[k-1]^2, f1p=xp+fp, fp+=4*fp, fp-=f1p,
        !           171:    fp+=2*(-1)^n, etc.  */
        !           172:
        !           173: mp_size_t
        !           174: mpn_fib2_ui (mp_ptr fp, mp_ptr f1p, unsigned long int n)
        !           175: {
        !           176:   mp_ptr         xp, yp;
        !           177:   mp_size_t      size;
        !           178:   unsigned long  nfirst, mask;
        !           179:   TMP_DECL (marker);
        !           180:
        !           181:   TRACE (printf ("mpn_fib2_ui n=%lu\n", n));
        !           182:
        !           183:   ASSERT (! MPN_OVERLAP_P (fp, MPN_FIB2_SIZE(n), f1p, MPN_FIB2_SIZE(n)));
        !           184:
        !           185:   /* Take a starting pair from the table. */
        !           186:   mask = 1;
        !           187:   for (nfirst = n; nfirst > FIB_TABLE_LIMIT; nfirst /= 2)
        !           188:     mask <<= 1;
        !           189:   TRACE (printf ("nfirst=%lu mask=0x%lX\n", nfirst, mask));
        !           190:
        !           191:   f1p[0] = FIB_TABLE ((int) nfirst - 1);
        !           192:   fp[0]  = FIB_TABLE (nfirst);
        !           193:   size = 1;
        !           194:
        !           195:   /* Skip to the end if the table lookup gives the final answer. */
        !           196:   if (mask != 1)
        !           197:     {
        !           198:       mp_size_t  alloc;
        !           199:
        !           200:       TMP_MARK (marker);
        !           201:       alloc = MPN_FIB2_SIZE (n);
        !           202:       TMP_ALLOC_LIMBS_2 (xp,alloc, yp,alloc);
        !           203:
        !           204:       do
        !           205:        {
        !           206:          mp_limb_t  c;
        !           207:
        !           208:          /* Here fp==F[k] and f1p==F[k-1], with k being the bits of n from
        !           209:             n&mask upwards.
        !           210:
        !           211:             The next bit of n is n&(mask>>1) and we'll double to the pair
        !           212:             fp==F[2k],f1p==F[2k-1] or fp==F[2k+1],f1p==F[2k], according as
        !           213:             that bit is 0 or 1 respectively.  */
        !           214:
        !           215:          TRACE (printf ("k=%lu mask=0x%lX size=%ld alloc=%ld\n",
        !           216:                         n >> refmpn_count_trailing_zeros(mask),
        !           217:                         mask, size, alloc);
        !           218:                 mpn_trace ("fp ", fp, size);
        !           219:                 mpn_trace ("f1p", f1p, size));
        !           220:
        !           221:          /* fp normalized, f1p at most one high zero */
        !           222:          ASSERT (fp[size-1] != 0);
        !           223:          ASSERT (f1p[size-1] != 0 || f1p[size-2] != 0);
        !           224:
        !           225:          /* f1p[size-1] might be zero, but this occurs rarely, so it's not
        !           226:             worth bothering checking for it */
        !           227:          ASSERT (alloc >= 2*size);
        !           228:          mpn_sqr_n (xp, fp,  size);
        !           229:          mpn_sqr_n (yp, f1p, size);
        !           230:          size *= 2;
        !           231:
        !           232:          /* Shrink if possible.  Since fp was normalized there'll be at
        !           233:             most one high zero on xp (and if there is then there's one on
        !           234:             yp too).  */
        !           235:          ASSERT (xp[size-1] != 0 || yp[size-1] == 0);
        !           236:          size -= (xp[size-1] == 0);
        !           237:          ASSERT (xp[size-1] != 0);  /* only one xp high zero */
        !           238:
        !           239:          /* Calculate F[2k+1] = 4*F[k]^2 - F[k-1]^2 + 2*(-1)^k.
        !           240:             n&mask is the low bit of our implied k.  */
        !           241:          c = mpn_lshift (fp, xp, size, 2);
        !           242:          fp[0] |= (n & mask ? 0 : 2);   /* possible +2 */
        !           243:          c -= mpn_sub_n (fp, fp, yp, size);
        !           244:          ASSERT (n & (mask << 1) ? fp[0] != 0 && fp[0] != 1 : 1);
        !           245:          fp[0] -= (n & mask ? 2 : 0);   /* possible -2 */
        !           246:          ASSERT (alloc >= size+1);
        !           247:          xp[size] = 0;
        !           248:          yp[size] = 0;
        !           249:          fp[size] = c;
        !           250:          size += (c != 0);
        !           251:
        !           252:          /* Calculate F[2k-1] = F[k]^2 + F[k-1]^2.
        !           253:             F[2k-1]<F[2k+1] so no carry out of "size" limbs. */
        !           254:          ASSERT_NOCARRY (mpn_add_n (f1p, xp, yp, size));
        !           255:
        !           256:          /* now n&mask is the new bit of n being considered */
        !           257:          mask >>= 1;
        !           258:
        !           259:          /* Calculate F[2k] = F[2k+1] - F[2k-1], replacing the unwanted one of
        !           260:             F[2k+1] and F[2k-1].  */
        !           261:          ASSERT_NOCARRY (mpn_sub_n ((n & mask ? f1p : fp), fp, f1p, size));
        !           262:
        !           263:          /* Can have a high zero after replacing F[2k+1] with F[2k].
        !           264:             f1p will have a high zero if fp does. */
        !           265:          ASSERT (fp[size-1] != 0 || f1p[size-1] == 0);
        !           266:          size -= (fp[size-1] == 0);
        !           267:        }
        !           268:       while (mask != 1);
        !           269:
        !           270:       TMP_FREE (marker);
        !           271:     }
        !           272:
        !           273:   TRACE (printf ("done size=%ld\n", size);
        !           274:         mpn_trace ("fp ", fp, size);
        !           275:         mpn_trace ("f1p", f1p, size));
        !           276:
        !           277:   return size;
        !           278: }
        !           279:
        !           280:
        !           281:
        !           282:
        !           283:
        !           284: /* ------------------------------------------------------------------------- */
        !           285:
        !           286: #if GENERATE_FIB_TABLE
        !           287: /* Generate the tables of fibonacci data.  This doesn't depend on the limb
        !           288:    size of the host, and doesn't need mpz_fib_ui working.
        !           289:
        !           290:    The bit sizes in the table[] below will get specific setups so that a
        !           291:    build with GMP_NUMB_BITS equal to one of those values has as much data in
        !           292:    __gmp_fib_table as will fit that number of bits.
        !           293:
        !           294:    A build with GMP_NUMB_BITS equal to some other value will effectively
        !           295:    fall back to the previous set of generated data.  For instance if 8 and
        !           296:    16 bits have been generated, but a build with 13 bits is done then
        !           297:    __gmp_fib_table will only contain 8 bit values, whereas it could probably
        !           298:    fit a few more.  Everything still works, it's just that the table scheme
        !           299:    is not fully exploited.  */
        !           300:
        !           301: int
        !           302: main (void)
        !           303: {
        !           304:   static struct {
        !           305:     int  bits;
        !           306:     int  fib_limit;
        !           307:     int  luc_limit;
        !           308:   } table[] = {
        !           309:     { 4 },
        !           310:     { 8 },
        !           311:     { 16 },
        !           312:     { 32 },
        !           313:     { 64 },
        !           314:   };
        !           315:
        !           316:   int    i, t;
        !           317:   mpz_t  f[500];
        !           318:   mpz_t  l;
        !           319:
        !           320:   mpz_init (l);
        !           321:   mpz_init_set_si (f[0], 1L);  /* F[-1] */
        !           322:   mpz_init_set_si (f[1], 0L);  /* F[0] */
        !           323:   for (i = 2; i < numberof(f); i++)
        !           324:     {
        !           325:       mpz_init (f[i]);
        !           326:       mpz_add (f[i], f[i-1], f[i-2]);
        !           327:     }
        !           328:
        !           329:   for (i = 1; i < numberof (f); i++)
        !           330:     {
        !           331:       /* L[n] = F[n]+2*F[n-1] */
        !           332:       mpz_add (l, f[i], f[i-1]);
        !           333:       mpz_add (l, l, f[i-1]);
        !           334:
        !           335:       for (t = 0; t < numberof (table); t++)
        !           336:        {
        !           337:          if (mpz_sizeinbase (f[i], 2) <= table[t].bits)
        !           338:            table[t].fib_limit = i-1;
        !           339:          if (mpz_sizeinbase (l, 2) <= table[t].bits)
        !           340:            table[t].luc_limit = i-1;
        !           341:        }
        !           342:     }
        !           343:   if (table[t].fib_limit == numberof (f) + 1)
        !           344:     {
        !           345:       printf ("Oops, need bigger f[] array\n");
        !           346:       abort ();
        !           347:     }
        !           348:
        !           349:   for (t = numberof (table) - 1; t >= 0; t--)
        !           350:     {
        !           351:       printf ("#if GMP_NUMB_BITS >= %d\n", table[t].bits);
        !           352:       printf ("#define FIB_TABLE_LIMIT         %d\n", table[t].fib_limit);
        !           353:       printf ("#define FIB_TABLE_LUCNUM_LIMIT  %d\n", table[t].luc_limit);
        !           354:       if (t != 0)
        !           355:        printf ("#else\n");
        !           356:     }
        !           357:   for (t = 0; t < numberof (table); t++)
        !           358:     printf ("#endif /* %d */\n", table[t].bits);
        !           359:   printf ("\n");
        !           360:   printf ("\n");
        !           361:
        !           362:   printf ("const mp_limb_t\n");
        !           363:   printf ("__gmp_fib_table[FIB_TABLE_LIMIT+2] = {\n");
        !           364:   printf ("\n");
        !           365:   t = 0;
        !           366:   i = 0;
        !           367:   printf ("#if GMP_NUMB_BITS >= %d\n", table[t].bits);
        !           368:   for (;;)
        !           369:     {
        !           370:       gmp_printf ("  CNST_LIMB (0x%ZX),  /* %d */\n", f[i], i-1);
        !           371:
        !           372:       if (i-1 == table[t].fib_limit)
        !           373:        {
        !           374:          printf ("#endif\n");
        !           375:          do
        !           376:            {
        !           377:              t++;
        !           378:              if (t >= numberof (table))
        !           379:                goto done;
        !           380:            }
        !           381:          while (i-1 == table[t].fib_limit);
        !           382:          printf ("#if GMP_NUMB_BITS >= %d\n", table[t].bits);
        !           383:        }
        !           384:       i++;
        !           385:     }
        !           386:  done:
        !           387:   printf ("};\n");
        !           388:
        !           389:   return 0;
        !           390: }
        !           391:
        !           392: #endif

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