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

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

1.1     ! maekawa     1: /* mpn_divrem_2 -- Divide natural numbers, producing both remainder and
        !             2:    quotient.  The divisor is two limbs.
        !             3:
        !             4:    THIS FILE CONTAINS INTERNAL FUNCTIONS WITH MUTABLE INTERFACES.  IT IS
        !             5:    ONLY SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS
        !             6:    ALMOST GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP
        !             7:    RELEASE.
        !             8:
        !             9:
        !            10: Copyright (C) 1993, 1994, 1995, 1996, 1999, 2000 Free Software Foundation,
        !            11: Inc.
        !            12:
        !            13: This file is part of the GNU MP Library.
        !            14:
        !            15: The GNU MP Library is free software; you can redistribute it and/or modify
        !            16: it under the terms of the GNU Lesser General Public License as published by
        !            17: the Free Software Foundation; either version 2.1 of the License, or (at your
        !            18: option) any later version.
        !            19:
        !            20: The GNU MP Library is distributed in the hope that it will be useful, but
        !            21: WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            22: or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
        !            23: License for more details.
        !            24:
        !            25: You should have received a copy of the GNU Lesser General Public License
        !            26: along with the GNU MP Library; see the file COPYING.LIB.  If not, write to
        !            27: the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
        !            28: MA 02111-1307, USA. */
        !            29:
        !            30: #include "gmp.h"
        !            31: #include "gmp-impl.h"
        !            32: #include "longlong.h"
        !            33:
        !            34: /* Divide num (NP/NSIZE) by den (DP/2) and write
        !            35:    the NSIZE-2 least significant quotient limbs at QP
        !            36:    and the 2 long remainder at NP.  If QEXTRA_LIMBS is
        !            37:    non-zero, generate that many fraction bits and append them after the
        !            38:    other quotient limbs.
        !            39:    Return the most significant limb of the quotient, this is always 0 or 1.
        !            40:
        !            41:    Preconditions:
        !            42:    0. NSIZE >= 2.
        !            43:    1. The most significant bit of the divisor must be set.
        !            44:    2. QP must either not overlap with the input operands at all, or
        !            45:       QP + 2 >= NP must hold true.  (This means that it's
        !            46:       possible to put the quotient in the high part of NUM, right after the
        !            47:       remainder in NUM.
        !            48:    3. NSIZE >= 2, even if QEXTRA_LIMBS is non-zero.  */
        !            49:
        !            50: mp_limb_t
        !            51: #if __STDC__
        !            52: mpn_divrem_2 (mp_ptr qp, mp_size_t qxn,
        !            53:              mp_ptr np, mp_size_t nsize,
        !            54:              mp_srcptr dp)
        !            55: #else
        !            56: mpn_divrem_2 (qp, qxn, np, nsize, dp)
        !            57:      mp_ptr qp;
        !            58:      mp_size_t qxn;
        !            59:      mp_ptr np;
        !            60:      mp_size_t nsize;
        !            61:      mp_srcptr dp;
        !            62: #endif
        !            63: {
        !            64:   mp_limb_t most_significant_q_limb = 0;
        !            65:   mp_size_t i;
        !            66:   mp_limb_t n1, n0, n2;
        !            67:   mp_limb_t d1, d0;
        !            68:   mp_limb_t d1inv;
        !            69:   int have_preinv;
        !            70:
        !            71:   np += nsize - 2;
        !            72:   d1 = dp[1];
        !            73:   d0 = dp[0];
        !            74:   n1 = np[1];
        !            75:   n0 = np[0];
        !            76:
        !            77:   if (n1 >= d1 && (n1 > d1 || n0 >= d0))
        !            78:     {
        !            79:       sub_ddmmss (n1, n0, n1, n0, d1, d0);
        !            80:       most_significant_q_limb = 1;
        !            81:     }
        !            82:
        !            83:   /* If multiplication is much faster than division, preinvert the most
        !            84:      significant divisor limb before entering the loop.  */
        !            85:   if (UDIV_TIME > 2 * UMUL_TIME + 6)
        !            86:     {
        !            87:       have_preinv = 0;
        !            88:       if ((UDIV_TIME - (2 * UMUL_TIME + 6)) * (nsize - 2) > UDIV_TIME)
        !            89:        {
        !            90:          invert_limb (d1inv, d1);
        !            91:          have_preinv = 1;
        !            92:        }
        !            93:     }
        !            94:
        !            95:   for (i = qxn + nsize - 2 - 1; i >= 0; i--)
        !            96:     {
        !            97:       mp_limb_t q;
        !            98:       mp_limb_t r;
        !            99:
        !           100:       if (i >= qxn)
        !           101:        np--;
        !           102:       else
        !           103:        np[0] = 0;
        !           104:
        !           105:       if (n1 == d1)
        !           106:        {
        !           107:          /* Q should be either 111..111 or 111..110.  Need special treatment
        !           108:             of this rare case as normal division would give overflow.  */
        !           109:          q = ~(mp_limb_t) 0;
        !           110:
        !           111:          r = n0 + d1;
        !           112:          if (r < d1)   /* Carry in the addition? */
        !           113:            {
        !           114:              add_ssaaaa (n1, n0, r - d0, np[0], 0, d0);
        !           115:              qp[i] = q;
        !           116:              continue;
        !           117:            }
        !           118:          n1 = d0 - (d0 != 0);
        !           119:          n0 = -d0;
        !           120:        }
        !           121:       else
        !           122:        {
        !           123:          if (UDIV_TIME > 2 * UMUL_TIME + 6 && have_preinv)
        !           124:            udiv_qrnnd_preinv (q, r, n1, n0, d1, d1inv);
        !           125:          else
        !           126:            udiv_qrnnd (q, r, n1, n0, d1);
        !           127:          umul_ppmm (n1, n0, d0, q);
        !           128:        }
        !           129:
        !           130:       n2 = np[0];
        !           131:
        !           132:     q_test:
        !           133:       if (n1 > r || (n1 == r && n0 > n2))
        !           134:        {
        !           135:          /* The estimated Q was too large.  */
        !           136:          q--;
        !           137:
        !           138:          sub_ddmmss (n1, n0, n1, n0, 0, d0);
        !           139:          r += d1;
        !           140:          if (r >= d1)  /* If not carry, test Q again.  */
        !           141:            goto q_test;
        !           142:        }
        !           143:
        !           144:       qp[i] = q;
        !           145:       sub_ddmmss (n1, n0, r, n2, n1, n0);
        !           146:     }
        !           147:   np[1] = n1;
        !           148:   np[0] = n0;
        !           149:
        !           150:   return most_significant_q_limb;
        !           151: }

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