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

Annotation of OpenXM_contrib/gmp/mpz/bin_ui.c, Revision 1.1

1.1     ! maekawa     1: /* mpz_bin_uiui - compute n over k.
        !             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: #include "longlong.h"
        !            25:
        !            26:
        !            27: /* This is a poor implementation.  Look at bin_uiui.c for improvement ideas.
        !            28:    In fact consider calling mpz_bin_uiui() when the arguments fit, leaving
        !            29:    the code here only for big n.
        !            30:
        !            31:    The identity bin(n,k) = (-1)^k * bin(-n+k-1,k) can be found in Knuth vol
        !            32:    1 section 1.2.6 part G. */
        !            33:
        !            34:
        !            35: /* Enhancement: use mpn_divexact_1 when it exists */
        !            36: #define DIVIDE()                                        \
        !            37:   ASSERT (SIZ(r) > 0);                                  \
        !            38:   ASSERT_NOCARRY (mpn_divrem_1 (PTR(r), (mp_size_t) 0,  \
        !            39:                                 PTR(r), SIZ(r), kacc)); \
        !            40:   SIZ(r) -= (PTR(r)[SIZ(r)-1] == 0);
        !            41:
        !            42: void
        !            43: #if __STDC__
        !            44: mpz_bin_ui (mpz_ptr r, mpz_srcptr n, unsigned long int k)
        !            45: #else
        !            46: mpz_bin_ui (r, n, k)
        !            47:      mpz_ptr r;
        !            48:      mpz_srcptr n;
        !            49:      unsigned long int k;
        !            50: #endif
        !            51: {
        !            52:   mpz_t      ni;
        !            53:   mp_limb_t  i;
        !            54:   mpz_t      nacc;
        !            55:   mp_limb_t  kacc;
        !            56:   mp_size_t  negate;
        !            57:
        !            58:   if (mpz_sgn (n) < 0)
        !            59:     {
        !            60:       /* bin(n,k) = (-1)^k * bin(-n+k-1,k), and set ni = -n+k-1 - k = -n-1 */
        !            61:       mpz_init (ni);
        !            62:       mpz_neg (ni, n);
        !            63:       mpz_sub_ui (ni, ni, 1L);
        !            64:       negate = (k & 1);   /* (-1)^k */
        !            65:     }
        !            66:   else
        !            67:     {
        !            68:       /* bin(n,k) == 0 if k>n
        !            69:          (no test for this under the n<0 case, since -n+k-1 >= k there) */
        !            70:       if (mpz_cmp_ui (n, k) < 0)
        !            71:         {
        !            72:           mpz_set_ui (r, 0L);
        !            73:           return;
        !            74:         }
        !            75:
        !            76:       /* set ni = n-k */
        !            77:       mpz_init (ni);
        !            78:       mpz_sub_ui (ni, n, k);
        !            79:       negate = 0;
        !            80:     }
        !            81:
        !            82:   /* Now wanting bin(ni+k,k), with ni positive, and "negate" is the sign (0
        !            83:      for positive, 1 for negative). */
        !            84:   mpz_set_ui (r, 1L);
        !            85:
        !            86:   /* Rewrite bin(n,k) as bin(n,n-k) if that is smaller.  In this case it's
        !            87:      whether ni+k-k < k meaning ni<k, and if so change to denominator ni+k-k
        !            88:      = ni, and new ni of ni+k-ni = k.  */
        !            89:   if (mpz_cmp_ui (ni, k) < 0)
        !            90:     {
        !            91:       unsigned long  tmp;
        !            92:       tmp = k;
        !            93:       k = mpz_get_ui (ni);
        !            94:       mpz_set_ui (ni, tmp);
        !            95:     }
        !            96:
        !            97:   kacc = 1;
        !            98:   mpz_init_set_ui (nacc, 1);
        !            99:
        !           100:   for (i = 1; i <= k; i++)
        !           101:     {
        !           102:       mp_limb_t k1, k0;
        !           103:
        !           104: #if 0
        !           105:       mp_limb_t nacclow;
        !           106:       int c;
        !           107:
        !           108:       nacclow = PTR(nacc)[0];
        !           109:       for (c = 0; (((kacc | nacclow) & 1) == 0); c++)
        !           110:        {
        !           111:          kacc >>= 1;
        !           112:          nacclow >>= 1;
        !           113:        }
        !           114:       mpz_div_2exp (nacc, nacc, c);
        !           115: #endif
        !           116:
        !           117:       mpz_add_ui (ni, ni, 1);
        !           118:       mpz_mul (nacc, nacc, ni);
        !           119:       umul_ppmm (k1, k0, kacc, i);
        !           120:       if (k1 != 0)
        !           121:        {
        !           122:          /* Accumulator overflow.  Perform bignum step.  */
        !           123:          mpz_mul (r, r, nacc);
        !           124:          mpz_set_ui (nacc, 1);
        !           125:           DIVIDE ();
        !           126:          kacc = i;
        !           127:        }
        !           128:       else
        !           129:        {
        !           130:          /* Save new products in accumulators to keep accumulating.  */
        !           131:          kacc = k0;
        !           132:        }
        !           133:     }
        !           134:
        !           135:   mpz_mul (r, r, nacc);
        !           136:   DIVIDE ();
        !           137:   SIZ(r) = (SIZ(r) ^ -negate) + negate;
        !           138:
        !           139:   mpz_clear (nacc);
        !           140:   mpz_clear (ni);
        !           141: }

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