xref: /dragonfly/contrib/gmp/mpz/aors.h (revision cd1c6085)
1 /* mpz_add, mpz_sub -- add or subtract integers.
2 
3 Copyright 1991, 1993, 1994, 1996, 2000, 2001 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 3 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.  If not, see http://www.gnu.org/licenses/.  */
19 
20 #include "gmp.h"
21 #include "gmp-impl.h"
22 
23 
24 #ifdef BERKELEY_MP
25 
26 #include "mp.h"
27 #ifdef OPERATION_add
28 #define FUNCTION     madd
29 #define VARIATION
30 #endif
31 #ifdef OPERATION_sub
32 #define FUNCTION     msub
33 #define VARIATION    -
34 #endif
35 #define ARGUMENTS    mpz_srcptr u, mpz_srcptr v, mpz_ptr w
36 
37 #else /* normal GMP */
38 
39 #ifdef OPERATION_add
40 #define FUNCTION     mpz_add
41 #define VARIATION
42 #endif
43 #ifdef OPERATION_sub
44 #define FUNCTION     mpz_sub
45 #define VARIATION    -
46 #endif
47 #define ARGUMENTS    mpz_ptr w, mpz_srcptr u, mpz_srcptr v
48 
49 #endif
50 
51 #ifndef FUNCTION
52 Error, need OPERATION_add or OPERATION_sub
53 #endif
54 
55 
56 void
57 FUNCTION (ARGUMENTS)
58 {
59   mp_srcptr up, vp;
60   mp_ptr wp;
61   mp_size_t usize, vsize, wsize;
62   mp_size_t abs_usize;
63   mp_size_t abs_vsize;
64 
65   usize = u->_mp_size;
66   vsize = VARIATION v->_mp_size;
67   abs_usize = ABS (usize);
68   abs_vsize = ABS (vsize);
69 
70   if (abs_usize < abs_vsize)
71     {
72       /* Swap U and V. */
73       MPZ_SRCPTR_SWAP (u, v);
74       MP_SIZE_T_SWAP (usize, vsize);
75       MP_SIZE_T_SWAP (abs_usize, abs_vsize);
76     }
77 
78   /* True: ABS_USIZE >= ABS_VSIZE.  */
79 
80   /* If not space for w (and possible carry), increase space.  */
81   wsize = abs_usize + 1;
82   if (w->_mp_alloc < wsize)
83     _mpz_realloc (w, wsize);
84 
85   /* These must be after realloc (u or v may be the same as w).  */
86   up = u->_mp_d;
87   vp = v->_mp_d;
88   wp = w->_mp_d;
89 
90   if ((usize ^ vsize) < 0)
91     {
92       /* U and V have different sign.  Need to compare them to determine
93 	 which operand to subtract from which.  */
94 
95       /* This test is right since ABS_USIZE >= ABS_VSIZE.  */
96       if (abs_usize != abs_vsize)
97 	{
98 	  mpn_sub (wp, up, abs_usize, vp, abs_vsize);
99 	  wsize = abs_usize;
100 	  MPN_NORMALIZE (wp, wsize);
101 	  if (usize < 0)
102 	    wsize = -wsize;
103 	}
104       else if (mpn_cmp (up, vp, abs_usize) < 0)
105 	{
106 	  mpn_sub_n (wp, vp, up, abs_usize);
107 	  wsize = abs_usize;
108 	  MPN_NORMALIZE (wp, wsize);
109 	  if (usize >= 0)
110 	    wsize = -wsize;
111 	}
112       else
113 	{
114 	  mpn_sub_n (wp, up, vp, abs_usize);
115 	  wsize = abs_usize;
116 	  MPN_NORMALIZE (wp, wsize);
117 	  if (usize < 0)
118 	    wsize = -wsize;
119 	}
120     }
121   else
122     {
123       /* U and V have same sign.  Add them.  */
124       mp_limb_t cy_limb = mpn_add (wp, up, abs_usize, vp, abs_vsize);
125       wp[abs_usize] = cy_limb;
126       wsize = abs_usize + cy_limb;
127       if (usize < 0)
128 	wsize = -wsize;
129     }
130 
131   w->_mp_size = wsize;
132 }
133