1 /* mpz_addmul, mpz_submul -- add or subtract multiple.
2 
3 Copyright 2001, 2004, 2005, 2012 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 either:
9 
10   * the GNU Lesser General Public License as published by the Free
11     Software Foundation; either version 3 of the License, or (at your
12     option) any later version.
13 
14 or
15 
16   * the GNU General Public License as published by the Free Software
17     Foundation; either version 2 of the License, or (at your option) any
18     later version.
19 
20 or both in parallel, as here.
21 
22 The GNU MP Library is distributed in the hope that it will be useful, but
23 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
25 for more details.
26 
27 You should have received copies of the GNU General Public License and the
28 GNU Lesser General Public License along with the GNU MP Library.  If not,
29 see https://www.gnu.org/licenses/.  */
30 
31 #include "gmp-impl.h"
32 
33 
34 /* expecting x and y both with non-zero high limbs */
35 #define mpn_cmp_twosizes_lt(xp,xsize, yp,ysize)                 \
36   ((xsize) < (ysize)                                            \
37    || ((xsize) == (ysize) && mpn_cmp (xp, yp, xsize) < 0))
38 
39 
40 /* sub>=0 means an addmul w += x*y, sub<0 means a submul w -= x*y.
41 
42    The signs of w, x and y are fully accounted for by each flipping "sub".
43 
44    The sign of w is retained for the result, unless the absolute value
45    submul underflows, in which case it flips.  */
46 
47 static void __gmpz_aorsmul (REGPARM_3_1 (mpz_ptr w, mpz_srcptr x, mpz_srcptr y, mp_size_t sub)) REGPARM_ATTR (1);
48 #define mpz_aorsmul(w,x,y,sub)  __gmpz_aorsmul (REGPARM_3_1 (w, x, y, sub))
49 
50 REGPARM_ATTR (1) static void
mpz_aorsmul(mpz_ptr w,mpz_srcptr x,mpz_srcptr y,mp_size_t sub)51 mpz_aorsmul (mpz_ptr w, mpz_srcptr x, mpz_srcptr y, mp_size_t sub)
52 {
53   mp_size_t  xsize, ysize, tsize, wsize, wsize_signed;
54   mp_ptr     wp, tp;
55   mp_limb_t  c, high;
56   TMP_DECL;
57 
58   /* w unaffected if x==0 or y==0 */
59   xsize = SIZ(x);
60   ysize = SIZ(y);
61   if (xsize == 0 || ysize == 0)
62     return;
63 
64   /* make x the bigger of the two */
65   if (ABS(ysize) > ABS(xsize))
66     {
67       MPZ_SRCPTR_SWAP (x, y);
68       MP_SIZE_T_SWAP (xsize, ysize);
69     }
70 
71   sub ^= ysize;
72   ysize = ABS(ysize);
73 
74   /* use mpn_addmul_1/mpn_submul_1 if possible */
75   if (ysize == 1)
76     {
77       mpz_aorsmul_1 (w, x, PTR(y)[0], sub);
78       return;
79     }
80 
81   sub ^= xsize;
82   xsize = ABS(xsize);
83 
84   wsize_signed = SIZ(w);
85   sub ^= wsize_signed;
86   wsize = ABS(wsize_signed);
87 
88   tsize = xsize + ysize;
89   wp = MPZ_REALLOC (w, MAX (wsize, tsize) + 1);
90 
91   if (wsize_signed == 0)
92     {
93       /* Nothing to add to, just set w=x*y.  No w==x or w==y overlap here,
94            since we know x,y!=0 but w==0.  */
95       high = mpn_mul (wp, PTR(x),xsize, PTR(y),ysize);
96       tsize -= (high == 0);
97       SIZ(w) = (sub >= 0 ? tsize : -tsize);
98       return;
99     }
100 
101   TMP_MARK;
102   tp = TMP_ALLOC_LIMBS (tsize);
103 
104   high = mpn_mul (tp, PTR(x),xsize, PTR(y),ysize);
105   tsize -= (high == 0);
106   ASSERT (tp[tsize-1] != 0);
107   if (sub >= 0)
108     {
109       mp_srcptr up    = wp;
110       mp_size_t usize = wsize;
111 
112       if (usize < tsize)
113           {
114             up      = tp;
115             usize = tsize;
116             tp      = wp;
117             tsize = wsize;
118 
119             wsize = usize;
120           }
121 
122       c = mpn_add (wp, up,usize, tp,tsize);
123       wp[wsize] = c;
124       wsize += (c != 0);
125     }
126   else
127     {
128       mp_srcptr up    = wp;
129       mp_size_t usize = wsize;
130 
131       if (mpn_cmp_twosizes_lt (up,usize, tp,tsize))
132           {
133             up      = tp;
134             usize = tsize;
135             tp      = wp;
136             tsize = wsize;
137 
138             wsize = usize;
139             wsize_signed = -wsize_signed;
140           }
141 
142       ASSERT_NOCARRY (mpn_sub (wp, up,usize, tp,tsize));
143       wsize = usize;
144       MPN_NORMALIZE (wp, wsize);
145     }
146 
147   SIZ(w) = (wsize_signed >= 0 ? wsize : -wsize);
148 
149   TMP_FREE;
150 }
151 
152 
153 void
mpz_addmul(mpz_ptr w,mpz_srcptr u,mpz_srcptr v)154 mpz_addmul (mpz_ptr w, mpz_srcptr u, mpz_srcptr v)
155 {
156   mpz_aorsmul (w, u, v, (mp_size_t) 0);
157 }
158 
159 void
mpz_submul(mpz_ptr w,mpz_srcptr u,mpz_srcptr v)160 mpz_submul (mpz_ptr w, mpz_srcptr u, mpz_srcptr v)
161 {
162   mpz_aorsmul (w, u, v, (mp_size_t) -1);
163 }
164