Home | History | Annotate | Line # | Download | only in mpz
      1      1.1  mrg /* mpz_divexact_gcd -- exact division optimized for GCDs.
      2      1.1  mrg 
      3      1.1  mrg    THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE AND ARE ALMOST CERTAIN TO
      4      1.1  mrg    BE SUBJECT TO INCOMPATIBLE CHANGES IN FUTURE GNU MP RELEASES.
      5      1.1  mrg 
      6  1.1.1.2  mrg Copyright 2000, 2005, 2011, 2012 Free Software Foundation, Inc.
      7      1.1  mrg 
      8      1.1  mrg This file is part of the GNU MP Library.
      9      1.1  mrg 
     10      1.1  mrg The GNU MP Library is free software; you can redistribute it and/or modify
     11  1.1.1.3  mrg it under the terms of either:
     12  1.1.1.3  mrg 
     13  1.1.1.3  mrg   * the GNU Lesser General Public License as published by the Free
     14  1.1.1.3  mrg     Software Foundation; either version 3 of the License, or (at your
     15  1.1.1.3  mrg     option) any later version.
     16  1.1.1.3  mrg 
     17  1.1.1.3  mrg or
     18  1.1.1.3  mrg 
     19  1.1.1.3  mrg   * the GNU General Public License as published by the Free Software
     20  1.1.1.3  mrg     Foundation; either version 2 of the License, or (at your option) any
     21  1.1.1.3  mrg     later version.
     22  1.1.1.3  mrg 
     23  1.1.1.3  mrg or both in parallel, as here.
     24      1.1  mrg 
     25      1.1  mrg The GNU MP Library is distributed in the hope that it will be useful, but
     26      1.1  mrg WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     27  1.1.1.3  mrg or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     28  1.1.1.3  mrg for more details.
     29      1.1  mrg 
     30  1.1.1.3  mrg You should have received copies of the GNU General Public License and the
     31  1.1.1.3  mrg GNU Lesser General Public License along with the GNU MP Library.  If not,
     32  1.1.1.3  mrg see https://www.gnu.org/licenses/.  */
     33      1.1  mrg 
     34      1.1  mrg #include "gmp-impl.h"
     35      1.1  mrg #include "longlong.h"
     36      1.1  mrg 
     37      1.1  mrg 
     38      1.1  mrg /* Set q to a/d, expecting d to be from a GCD and therefore usually small.
     39      1.1  mrg 
     40      1.1  mrg    The distribution of GCDs of random numbers can be found in Knuth volume 2
     41      1.1  mrg    section 4.5.2 theorem D.
     42      1.1  mrg 
     43      1.1  mrg             GCD     chance
     44      1.1  mrg              1       60.8%
     45      1.1  mrg             2^k      20.2%     (1<=k<32)
     46      1.1  mrg            3*2^k      9.0%     (1<=k<32)
     47      1.1  mrg            other     10.1%
     48      1.1  mrg 
     49      1.1  mrg    Only the low limb is examined for optimizations, since GCDs bigger than
     50      1.1  mrg    2^32 (or 2^64) will occur very infrequently.
     51      1.1  mrg 
     52      1.1  mrg    Future: This could change to an mpn_divexact_gcd, possibly partly
     53      1.1  mrg    inlined, if/when the relevant mpq functions change to an mpn based
     54      1.1  mrg    implementation.  */
     55      1.1  mrg 
     56      1.1  mrg 
     57  1.1.1.2  mrg #if GMP_NUMB_BITS % 2 == 0
     58      1.1  mrg static void
     59      1.1  mrg mpz_divexact_by3 (mpz_ptr q, mpz_srcptr a)
     60      1.1  mrg {
     61      1.1  mrg   mp_size_t  size = SIZ(a);
     62  1.1.1.2  mrg   mp_size_t  abs_size = ABS(size);
     63  1.1.1.2  mrg   mp_ptr     qp;
     64      1.1  mrg 
     65  1.1.1.2  mrg   qp = MPZ_REALLOC (q, abs_size);
     66      1.1  mrg 
     67  1.1.1.2  mrg   mpn_bdiv_dbm1 (qp, PTR(a), abs_size, GMP_NUMB_MASK / 3);
     68      1.1  mrg 
     69  1.1.1.2  mrg   abs_size -= (qp[abs_size-1] == 0);
     70  1.1.1.2  mrg   SIZ(q) = (size>0 ? abs_size : -abs_size);
     71  1.1.1.2  mrg }
     72  1.1.1.2  mrg #endif
     73  1.1.1.2  mrg 
     74  1.1.1.2  mrg #if GMP_NUMB_BITS % 4 == 0
     75  1.1.1.2  mrg static void
     76  1.1.1.2  mrg mpz_divexact_by5 (mpz_ptr q, mpz_srcptr a)
     77  1.1.1.2  mrg {
     78  1.1.1.2  mrg   mp_size_t  size = SIZ(a);
     79  1.1.1.2  mrg   mp_size_t  abs_size = ABS(size);
     80  1.1.1.2  mrg   mp_ptr     qp;
     81  1.1.1.2  mrg 
     82  1.1.1.2  mrg   qp = MPZ_REALLOC (q, abs_size);
     83  1.1.1.2  mrg 
     84  1.1.1.2  mrg   mpn_bdiv_dbm1 (qp, PTR(a), abs_size, GMP_NUMB_MASK / 5);
     85  1.1.1.2  mrg 
     86  1.1.1.2  mrg   abs_size -= (qp[abs_size-1] == 0);
     87  1.1.1.2  mrg   SIZ(q) = (size>0 ? abs_size : -abs_size);
     88  1.1.1.2  mrg }
     89  1.1.1.2  mrg #endif
     90  1.1.1.2  mrg 
     91  1.1.1.2  mrg static void
     92  1.1.1.2  mrg mpz_divexact_limb (mpz_ptr q, mpz_srcptr a, mp_limb_t d)
     93  1.1.1.2  mrg {
     94  1.1.1.2  mrg   mp_size_t  size = SIZ(a);
     95  1.1.1.2  mrg   mp_size_t  abs_size = ABS(size);
     96  1.1.1.2  mrg   mp_ptr     qp;
     97  1.1.1.2  mrg 
     98  1.1.1.2  mrg   qp = MPZ_REALLOC (q, abs_size);
     99  1.1.1.2  mrg 
    100  1.1.1.4  mrg   MPN_DIVREM_OR_DIVEXACT_1 (qp, PTR(a), abs_size, d);
    101  1.1.1.2  mrg 
    102  1.1.1.2  mrg   abs_size -= (qp[abs_size-1] == 0);
    103  1.1.1.4  mrg   SIZ(q) = (size > 0 ? abs_size : -abs_size);
    104      1.1  mrg }
    105      1.1  mrg 
    106      1.1  mrg void
    107      1.1  mrg mpz_divexact_gcd (mpz_ptr q, mpz_srcptr a, mpz_srcptr d)
    108      1.1  mrg {
    109      1.1  mrg   ASSERT (mpz_sgn (d) > 0);
    110      1.1  mrg 
    111  1.1.1.2  mrg   if (SIZ(a) == 0)
    112  1.1.1.2  mrg     {
    113  1.1.1.2  mrg       SIZ(q) = 0;
    114  1.1.1.2  mrg       return;
    115  1.1.1.2  mrg     }
    116  1.1.1.2  mrg 
    117      1.1  mrg   if (SIZ(d) == 1)
    118      1.1  mrg     {
    119      1.1  mrg       mp_limb_t  dl = PTR(d)[0];
    120      1.1  mrg       int        twos;
    121      1.1  mrg 
    122  1.1.1.2  mrg       if ((dl & 1) == 0)
    123  1.1.1.2  mrg 	{
    124  1.1.1.2  mrg 	  count_trailing_zeros (twos, dl);
    125  1.1.1.2  mrg 	  dl >>= twos;
    126  1.1.1.2  mrg 	  mpz_tdiv_q_2exp (q, a, twos);
    127  1.1.1.2  mrg 	  a = q;
    128  1.1.1.2  mrg 	}
    129      1.1  mrg 
    130      1.1  mrg       if (dl == 1)
    131  1.1.1.2  mrg 	{
    132  1.1.1.2  mrg 	  if (q != a)
    133  1.1.1.2  mrg 	    mpz_set (q, a);
    134  1.1.1.2  mrg 	  return;
    135  1.1.1.2  mrg 	}
    136  1.1.1.2  mrg #if GMP_NUMB_BITS % 2 == 0
    137      1.1  mrg       if (dl == 3)
    138  1.1.1.2  mrg 	{
    139  1.1.1.2  mrg 	  mpz_divexact_by3 (q, a);
    140  1.1.1.2  mrg 	  return;
    141  1.1.1.2  mrg 	}
    142  1.1.1.2  mrg #endif
    143  1.1.1.2  mrg #if GMP_NUMB_BITS % 4 == 0
    144  1.1.1.2  mrg       if (dl == 5)
    145  1.1.1.2  mrg 	{
    146  1.1.1.2  mrg 	  mpz_divexact_by5 (q, a);
    147  1.1.1.2  mrg 	  return;
    148  1.1.1.2  mrg 	}
    149  1.1.1.2  mrg #endif
    150  1.1.1.2  mrg 
    151  1.1.1.2  mrg       mpz_divexact_limb (q, a, dl);
    152  1.1.1.2  mrg       return;
    153      1.1  mrg     }
    154      1.1  mrg 
    155      1.1  mrg   mpz_divexact (q, a, d);
    156      1.1  mrg }
    157