Import gmp-4.3.1
[dragonfly.git] / contrib / gmp / mpz / aors.h
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 }