Home | History | Annotate | Line # | Download | only in generic
mulmid.c revision 1.1.1.1.4.2
      1  1.1.1.1.4.2  yamt /* mpn_mulmid -- middle product
      2  1.1.1.1.4.2  yamt 
      3  1.1.1.1.4.2  yamt    Contributed by David Harvey.
      4  1.1.1.1.4.2  yamt 
      5  1.1.1.1.4.2  yamt    THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
      6  1.1.1.1.4.2  yamt    SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
      7  1.1.1.1.4.2  yamt    GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
      8  1.1.1.1.4.2  yamt 
      9  1.1.1.1.4.2  yamt Copyright 2011 Free Software Foundation, Inc.
     10  1.1.1.1.4.2  yamt 
     11  1.1.1.1.4.2  yamt This file is part of the GNU MP Library.
     12  1.1.1.1.4.2  yamt 
     13  1.1.1.1.4.2  yamt The GNU MP Library is free software; you can redistribute it and/or modify
     14  1.1.1.1.4.2  yamt it under the terms of the GNU Lesser General Public License as published by
     15  1.1.1.1.4.2  yamt the Free Software Foundation; either version 3 of the License, or (at your
     16  1.1.1.1.4.2  yamt option) any later version.
     17  1.1.1.1.4.2  yamt 
     18  1.1.1.1.4.2  yamt The GNU MP Library is distributed in the hope that it will be useful, but
     19  1.1.1.1.4.2  yamt WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     20  1.1.1.1.4.2  yamt or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
     21  1.1.1.1.4.2  yamt License for more details.
     22  1.1.1.1.4.2  yamt 
     23  1.1.1.1.4.2  yamt You should have received a copy of the GNU Lesser General Public License
     24  1.1.1.1.4.2  yamt along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
     25  1.1.1.1.4.2  yamt 
     26  1.1.1.1.4.2  yamt 
     27  1.1.1.1.4.2  yamt #include "gmp.h"
     28  1.1.1.1.4.2  yamt #include "gmp-impl.h"
     29  1.1.1.1.4.2  yamt 
     30  1.1.1.1.4.2  yamt 
     31  1.1.1.1.4.2  yamt #define CHUNK (200 + MULMID_TOOM42_THRESHOLD)
     32  1.1.1.1.4.2  yamt 
     33  1.1.1.1.4.2  yamt 
     34  1.1.1.1.4.2  yamt void
     35  1.1.1.1.4.2  yamt mpn_mulmid (mp_ptr rp,
     36  1.1.1.1.4.2  yamt             mp_srcptr ap, mp_size_t an,
     37  1.1.1.1.4.2  yamt             mp_srcptr bp, mp_size_t bn)
     38  1.1.1.1.4.2  yamt {
     39  1.1.1.1.4.2  yamt   mp_size_t rn, k;
     40  1.1.1.1.4.2  yamt   mp_ptr scratch, temp;
     41  1.1.1.1.4.2  yamt 
     42  1.1.1.1.4.2  yamt   ASSERT (an >= bn);
     43  1.1.1.1.4.2  yamt   ASSERT (bn >= 1);
     44  1.1.1.1.4.2  yamt   ASSERT (! MPN_OVERLAP_P (rp, an - bn + 3, ap, an));
     45  1.1.1.1.4.2  yamt   ASSERT (! MPN_OVERLAP_P (rp, an - bn + 3, bp, bn));
     46  1.1.1.1.4.2  yamt 
     47  1.1.1.1.4.2  yamt   if (bn < MULMID_TOOM42_THRESHOLD)
     48  1.1.1.1.4.2  yamt     {
     49  1.1.1.1.4.2  yamt       /* region not tall enough to make toom42 worthwhile for any portion */
     50  1.1.1.1.4.2  yamt 
     51  1.1.1.1.4.2  yamt       if (an < CHUNK)
     52  1.1.1.1.4.2  yamt 	{
     53  1.1.1.1.4.2  yamt 	  /* region not too wide either, just call basecase directly */
     54  1.1.1.1.4.2  yamt 	  mpn_mulmid_basecase (rp, ap, an, bp, bn);
     55  1.1.1.1.4.2  yamt 	  return;
     56  1.1.1.1.4.2  yamt 	}
     57  1.1.1.1.4.2  yamt 
     58  1.1.1.1.4.2  yamt       /* Region quite wide. For better locality, use basecase on chunks:
     59  1.1.1.1.4.2  yamt 
     60  1.1.1.1.4.2  yamt 	 AAABBBCC..
     61  1.1.1.1.4.2  yamt 	 .AAABBBCC.
     62  1.1.1.1.4.2  yamt 	 ..AAABBBCC
     63  1.1.1.1.4.2  yamt       */
     64  1.1.1.1.4.2  yamt 
     65  1.1.1.1.4.2  yamt       k = CHUNK - bn + 1;    /* number of diagonals per chunk */
     66  1.1.1.1.4.2  yamt 
     67  1.1.1.1.4.2  yamt       /* first chunk (marked A in the above diagram) */
     68  1.1.1.1.4.2  yamt       mpn_mulmid_basecase (rp, ap, CHUNK, bp, bn);
     69  1.1.1.1.4.2  yamt 
     70  1.1.1.1.4.2  yamt       /* remaining chunks (B, C, etc) */
     71  1.1.1.1.4.2  yamt       an -= k;
     72  1.1.1.1.4.2  yamt 
     73  1.1.1.1.4.2  yamt       while (an >= CHUNK)
     74  1.1.1.1.4.2  yamt 	{
     75  1.1.1.1.4.2  yamt 	  mp_limb_t t0, t1, cy;
     76  1.1.1.1.4.2  yamt 	  ap += k, rp += k;
     77  1.1.1.1.4.2  yamt 	  t0 = rp[0], t1 = rp[1];
     78  1.1.1.1.4.2  yamt 	  mpn_mulmid_basecase (rp, ap, CHUNK, bp, bn);
     79  1.1.1.1.4.2  yamt 	  ADDC_LIMB (cy, rp[0], rp[0], t0);    /* add back saved limbs */
     80  1.1.1.1.4.2  yamt 	  MPN_INCR_U (rp + 1, k + 1, t1 + cy);
     81  1.1.1.1.4.2  yamt 	  an -= k;
     82  1.1.1.1.4.2  yamt 	}
     83  1.1.1.1.4.2  yamt 
     84  1.1.1.1.4.2  yamt       if (an >= bn)
     85  1.1.1.1.4.2  yamt 	{
     86  1.1.1.1.4.2  yamt 	  /* last remaining chunk */
     87  1.1.1.1.4.2  yamt 	  mp_limb_t t0, t1, cy;
     88  1.1.1.1.4.2  yamt 	  ap += k, rp += k;
     89  1.1.1.1.4.2  yamt 	  t0 = rp[0], t1 = rp[1];
     90  1.1.1.1.4.2  yamt 	  mpn_mulmid_basecase (rp, ap, an, bp, bn);
     91  1.1.1.1.4.2  yamt 	  ADDC_LIMB (cy, rp[0], rp[0], t0);
     92  1.1.1.1.4.2  yamt 	  MPN_INCR_U (rp + 1, an - bn + 2, t1 + cy);
     93  1.1.1.1.4.2  yamt 	}
     94  1.1.1.1.4.2  yamt 
     95  1.1.1.1.4.2  yamt       return;
     96  1.1.1.1.4.2  yamt     }
     97  1.1.1.1.4.2  yamt 
     98  1.1.1.1.4.2  yamt   /* region is tall enough for toom42 */
     99  1.1.1.1.4.2  yamt 
    100  1.1.1.1.4.2  yamt   rn = an - bn + 1;
    101  1.1.1.1.4.2  yamt 
    102  1.1.1.1.4.2  yamt   if (rn < MULMID_TOOM42_THRESHOLD)
    103  1.1.1.1.4.2  yamt     {
    104  1.1.1.1.4.2  yamt       /* region not wide enough to make toom42 worthwhile for any portion */
    105  1.1.1.1.4.2  yamt 
    106  1.1.1.1.4.2  yamt       TMP_DECL;
    107  1.1.1.1.4.2  yamt 
    108  1.1.1.1.4.2  yamt       if (bn < CHUNK)
    109  1.1.1.1.4.2  yamt 	{
    110  1.1.1.1.4.2  yamt 	  /* region not too tall either, just call basecase directly */
    111  1.1.1.1.4.2  yamt 	  mpn_mulmid_basecase (rp, ap, an, bp, bn);
    112  1.1.1.1.4.2  yamt 	  return;
    113  1.1.1.1.4.2  yamt 	}
    114  1.1.1.1.4.2  yamt 
    115  1.1.1.1.4.2  yamt       /* Region quite tall. For better locality, use basecase on chunks:
    116  1.1.1.1.4.2  yamt 
    117  1.1.1.1.4.2  yamt 	 AAAAA....
    118  1.1.1.1.4.2  yamt 	 .AAAAA...
    119  1.1.1.1.4.2  yamt 	 ..BBBBB..
    120  1.1.1.1.4.2  yamt 	 ...BBBBB.
    121  1.1.1.1.4.2  yamt 	 ....CCCCC
    122  1.1.1.1.4.2  yamt       */
    123  1.1.1.1.4.2  yamt 
    124  1.1.1.1.4.2  yamt       TMP_MARK;
    125  1.1.1.1.4.2  yamt 
    126  1.1.1.1.4.2  yamt       temp = TMP_ALLOC_LIMBS (rn + 2);
    127  1.1.1.1.4.2  yamt 
    128  1.1.1.1.4.2  yamt       /* first chunk (marked A in the above diagram) */
    129  1.1.1.1.4.2  yamt       bp += bn - CHUNK, an -= bn - CHUNK;
    130  1.1.1.1.4.2  yamt       mpn_mulmid_basecase (rp, ap, an, bp, CHUNK);
    131  1.1.1.1.4.2  yamt 
    132  1.1.1.1.4.2  yamt       /* remaining chunks (B, C, etc) */
    133  1.1.1.1.4.2  yamt       bn -= CHUNK;
    134  1.1.1.1.4.2  yamt 
    135  1.1.1.1.4.2  yamt       while (bn >= CHUNK)
    136  1.1.1.1.4.2  yamt 	{
    137  1.1.1.1.4.2  yamt 	  ap += CHUNK, bp -= CHUNK;
    138  1.1.1.1.4.2  yamt 	  mpn_mulmid_basecase (temp, ap, an, bp, CHUNK);
    139  1.1.1.1.4.2  yamt 	  mpn_add_n (rp, rp, temp, rn + 2);
    140  1.1.1.1.4.2  yamt 	  bn -= CHUNK;
    141  1.1.1.1.4.2  yamt 	}
    142  1.1.1.1.4.2  yamt 
    143  1.1.1.1.4.2  yamt       if (bn)
    144  1.1.1.1.4.2  yamt 	{
    145  1.1.1.1.4.2  yamt 	  /* last remaining chunk */
    146  1.1.1.1.4.2  yamt 	  ap += CHUNK, bp -= bn;
    147  1.1.1.1.4.2  yamt 	  mpn_mulmid_basecase (temp, ap, rn + bn - 1, bp, bn);
    148  1.1.1.1.4.2  yamt 	  mpn_add_n (rp, rp, temp, rn + 2);
    149  1.1.1.1.4.2  yamt 	}
    150  1.1.1.1.4.2  yamt 
    151  1.1.1.1.4.2  yamt       TMP_FREE;
    152  1.1.1.1.4.2  yamt       return;
    153  1.1.1.1.4.2  yamt     }
    154  1.1.1.1.4.2  yamt 
    155  1.1.1.1.4.2  yamt   /* we're definitely going to use toom42 somewhere */
    156  1.1.1.1.4.2  yamt 
    157  1.1.1.1.4.2  yamt   if (bn > rn)
    158  1.1.1.1.4.2  yamt     {
    159  1.1.1.1.4.2  yamt       /* slice region into chunks, use toom42 on all chunks except possibly
    160  1.1.1.1.4.2  yamt 	 the last:
    161  1.1.1.1.4.2  yamt 
    162  1.1.1.1.4.2  yamt          AA....
    163  1.1.1.1.4.2  yamt          .AA...
    164  1.1.1.1.4.2  yamt          ..BB..
    165  1.1.1.1.4.2  yamt          ...BB.
    166  1.1.1.1.4.2  yamt          ....CC
    167  1.1.1.1.4.2  yamt       */
    168  1.1.1.1.4.2  yamt 
    169  1.1.1.1.4.2  yamt       TMP_DECL;
    170  1.1.1.1.4.2  yamt       TMP_MARK;
    171  1.1.1.1.4.2  yamt 
    172  1.1.1.1.4.2  yamt       temp = TMP_ALLOC_LIMBS (rn + 2 + mpn_toom42_mulmid_itch (rn));
    173  1.1.1.1.4.2  yamt       scratch = temp + rn + 2;
    174  1.1.1.1.4.2  yamt 
    175  1.1.1.1.4.2  yamt       /* first chunk (marked A in the above diagram) */
    176  1.1.1.1.4.2  yamt       bp += bn - rn;
    177  1.1.1.1.4.2  yamt       mpn_toom42_mulmid (rp, ap, bp, rn, scratch);
    178  1.1.1.1.4.2  yamt 
    179  1.1.1.1.4.2  yamt       /* remaining chunks (B, C, etc) */
    180  1.1.1.1.4.2  yamt       bn -= rn;
    181  1.1.1.1.4.2  yamt 
    182  1.1.1.1.4.2  yamt       while (bn >= rn)
    183  1.1.1.1.4.2  yamt         {
    184  1.1.1.1.4.2  yamt           ap += rn, bp -= rn;
    185  1.1.1.1.4.2  yamt 	  mpn_toom42_mulmid (temp, ap, bp, rn, scratch);
    186  1.1.1.1.4.2  yamt           mpn_add_n (rp, rp, temp, rn + 2);
    187  1.1.1.1.4.2  yamt           bn -= rn;
    188  1.1.1.1.4.2  yamt         }
    189  1.1.1.1.4.2  yamt 
    190  1.1.1.1.4.2  yamt       if (bn)
    191  1.1.1.1.4.2  yamt         {
    192  1.1.1.1.4.2  yamt           /* last remaining chunk */
    193  1.1.1.1.4.2  yamt           ap += rn, bp -= bn;
    194  1.1.1.1.4.2  yamt 	  mpn_mulmid (temp, ap, rn + bn - 1, bp, bn);
    195  1.1.1.1.4.2  yamt           mpn_add_n (rp, rp, temp, rn + 2);
    196  1.1.1.1.4.2  yamt         }
    197  1.1.1.1.4.2  yamt 
    198  1.1.1.1.4.2  yamt       TMP_FREE;
    199  1.1.1.1.4.2  yamt     }
    200  1.1.1.1.4.2  yamt   else
    201  1.1.1.1.4.2  yamt     {
    202  1.1.1.1.4.2  yamt       /* slice region into chunks, use toom42 on all chunks except possibly
    203  1.1.1.1.4.2  yamt 	 the last:
    204  1.1.1.1.4.2  yamt 
    205  1.1.1.1.4.2  yamt          AAABBBCC..
    206  1.1.1.1.4.2  yamt          .AAABBBCC.
    207  1.1.1.1.4.2  yamt          ..AAABBBCC
    208  1.1.1.1.4.2  yamt       */
    209  1.1.1.1.4.2  yamt 
    210  1.1.1.1.4.2  yamt       TMP_DECL;
    211  1.1.1.1.4.2  yamt       TMP_MARK;
    212  1.1.1.1.4.2  yamt 
    213  1.1.1.1.4.2  yamt       scratch = TMP_ALLOC_LIMBS (mpn_toom42_mulmid_itch (bn));
    214  1.1.1.1.4.2  yamt 
    215  1.1.1.1.4.2  yamt       /* first chunk (marked A in the above diagram) */
    216  1.1.1.1.4.2  yamt       mpn_toom42_mulmid (rp, ap, bp, bn, scratch);
    217  1.1.1.1.4.2  yamt 
    218  1.1.1.1.4.2  yamt       /* remaining chunks (B, C, etc) */
    219  1.1.1.1.4.2  yamt       rn -= bn;
    220  1.1.1.1.4.2  yamt 
    221  1.1.1.1.4.2  yamt       while (rn >= bn)
    222  1.1.1.1.4.2  yamt         {
    223  1.1.1.1.4.2  yamt 	  mp_limb_t t0, t1, cy;
    224  1.1.1.1.4.2  yamt           ap += bn, rp += bn;
    225  1.1.1.1.4.2  yamt           t0 = rp[0], t1 = rp[1];
    226  1.1.1.1.4.2  yamt           mpn_toom42_mulmid (rp, ap, bp, bn, scratch);
    227  1.1.1.1.4.2  yamt 	  ADDC_LIMB (cy, rp[0], rp[0], t0);     /* add back saved limbs */
    228  1.1.1.1.4.2  yamt 	  MPN_INCR_U (rp + 1, bn + 1, t1 + cy);
    229  1.1.1.1.4.2  yamt 	  rn -= bn;
    230  1.1.1.1.4.2  yamt         }
    231  1.1.1.1.4.2  yamt 
    232  1.1.1.1.4.2  yamt       TMP_FREE;
    233  1.1.1.1.4.2  yamt 
    234  1.1.1.1.4.2  yamt       if (rn)
    235  1.1.1.1.4.2  yamt         {
    236  1.1.1.1.4.2  yamt           /* last remaining chunk */
    237  1.1.1.1.4.2  yamt 	  mp_limb_t t0, t1, cy;
    238  1.1.1.1.4.2  yamt           ap += bn, rp += bn;
    239  1.1.1.1.4.2  yamt           t0 = rp[0], t1 = rp[1];
    240  1.1.1.1.4.2  yamt           mpn_mulmid (rp, ap, rn + bn - 1, bp, bn);
    241  1.1.1.1.4.2  yamt 	  ADDC_LIMB (cy, rp[0], rp[0], t0);
    242  1.1.1.1.4.2  yamt 	  MPN_INCR_U (rp + 1, rn + 1, t1 + cy);
    243  1.1.1.1.4.2  yamt         }
    244  1.1.1.1.4.2  yamt     }
    245  1.1.1.1.4.2  yamt }
    246