1*86d7f5d3SJohn Marino /* mpz_add, mpz_sub -- add or subtract integers. 2*86d7f5d3SJohn Marino 3*86d7f5d3SJohn Marino Copyright 1991, 1993, 1994, 1996, 2000, 2001 Free Software Foundation, Inc. 4*86d7f5d3SJohn Marino 5*86d7f5d3SJohn Marino This file is part of the GNU MP Library. 6*86d7f5d3SJohn Marino 7*86d7f5d3SJohn Marino The GNU MP Library is free software; you can redistribute it and/or modify 8*86d7f5d3SJohn Marino it under the terms of the GNU Lesser General Public License as published by 9*86d7f5d3SJohn Marino the Free Software Foundation; either version 3 of the License, or (at your 10*86d7f5d3SJohn Marino option) any later version. 11*86d7f5d3SJohn Marino 12*86d7f5d3SJohn Marino The GNU MP Library is distributed in the hope that it will be useful, but 13*86d7f5d3SJohn Marino WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14*86d7f5d3SJohn Marino or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15*86d7f5d3SJohn Marino License for more details. 16*86d7f5d3SJohn Marino 17*86d7f5d3SJohn Marino You should have received a copy of the GNU Lesser General Public License 18*86d7f5d3SJohn Marino along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ 19*86d7f5d3SJohn Marino 20*86d7f5d3SJohn Marino #include "gmp.h" 21*86d7f5d3SJohn Marino #include "gmp-impl.h" 22*86d7f5d3SJohn Marino 23*86d7f5d3SJohn Marino 24*86d7f5d3SJohn Marino #ifdef BERKELEY_MP 25*86d7f5d3SJohn Marino 26*86d7f5d3SJohn Marino #include "mp.h" 27*86d7f5d3SJohn Marino #ifdef OPERATION_add 28*86d7f5d3SJohn Marino #define FUNCTION madd 29*86d7f5d3SJohn Marino #define VARIATION 30*86d7f5d3SJohn Marino #endif 31*86d7f5d3SJohn Marino #ifdef OPERATION_sub 32*86d7f5d3SJohn Marino #define FUNCTION msub 33*86d7f5d3SJohn Marino #define VARIATION - 34*86d7f5d3SJohn Marino #endif 35*86d7f5d3SJohn Marino #define ARGUMENTS mpz_srcptr u, mpz_srcptr v, mpz_ptr w 36*86d7f5d3SJohn Marino 37*86d7f5d3SJohn Marino #else /* normal GMP */ 38*86d7f5d3SJohn Marino 39*86d7f5d3SJohn Marino #ifdef OPERATION_add 40*86d7f5d3SJohn Marino #define FUNCTION mpz_add 41*86d7f5d3SJohn Marino #define VARIATION 42*86d7f5d3SJohn Marino #endif 43*86d7f5d3SJohn Marino #ifdef OPERATION_sub 44*86d7f5d3SJohn Marino #define FUNCTION mpz_sub 45*86d7f5d3SJohn Marino #define VARIATION - 46*86d7f5d3SJohn Marino #endif 47*86d7f5d3SJohn Marino #define ARGUMENTS mpz_ptr w, mpz_srcptr u, mpz_srcptr v 48*86d7f5d3SJohn Marino 49*86d7f5d3SJohn Marino #endif 50*86d7f5d3SJohn Marino 51*86d7f5d3SJohn Marino #ifndef FUNCTION 52*86d7f5d3SJohn Marino Error, need OPERATION_add or OPERATION_sub 53*86d7f5d3SJohn Marino #endif 54*86d7f5d3SJohn Marino 55*86d7f5d3SJohn Marino 56*86d7f5d3SJohn Marino void 57*86d7f5d3SJohn Marino FUNCTION (ARGUMENTS) 58*86d7f5d3SJohn Marino { 59*86d7f5d3SJohn Marino mp_srcptr up, vp; 60*86d7f5d3SJohn Marino mp_ptr wp; 61*86d7f5d3SJohn Marino mp_size_t usize, vsize, wsize; 62*86d7f5d3SJohn Marino mp_size_t abs_usize; 63*86d7f5d3SJohn Marino mp_size_t abs_vsize; 64*86d7f5d3SJohn Marino 65*86d7f5d3SJohn Marino usize = u->_mp_size; 66*86d7f5d3SJohn Marino vsize = VARIATION v->_mp_size; 67*86d7f5d3SJohn Marino abs_usize = ABS (usize); 68*86d7f5d3SJohn Marino abs_vsize = ABS (vsize); 69*86d7f5d3SJohn Marino 70*86d7f5d3SJohn Marino if (abs_usize < abs_vsize) 71*86d7f5d3SJohn Marino { 72*86d7f5d3SJohn Marino /* Swap U and V. */ 73*86d7f5d3SJohn Marino MPZ_SRCPTR_SWAP (u, v); 74*86d7f5d3SJohn Marino MP_SIZE_T_SWAP (usize, vsize); 75*86d7f5d3SJohn Marino MP_SIZE_T_SWAP (abs_usize, abs_vsize); 76*86d7f5d3SJohn Marino } 77*86d7f5d3SJohn Marino 78*86d7f5d3SJohn Marino /* True: ABS_USIZE >= ABS_VSIZE. */ 79*86d7f5d3SJohn Marino 80*86d7f5d3SJohn Marino /* If not space for w (and possible carry), increase space. */ 81*86d7f5d3SJohn Marino wsize = abs_usize + 1; 82*86d7f5d3SJohn Marino if (w->_mp_alloc < wsize) 83*86d7f5d3SJohn Marino _mpz_realloc (w, wsize); 84*86d7f5d3SJohn Marino 85*86d7f5d3SJohn Marino /* These must be after realloc (u or v may be the same as w). */ 86*86d7f5d3SJohn Marino up = u->_mp_d; 87*86d7f5d3SJohn Marino vp = v->_mp_d; 88*86d7f5d3SJohn Marino wp = w->_mp_d; 89*86d7f5d3SJohn Marino 90*86d7f5d3SJohn Marino if ((usize ^ vsize) < 0) 91*86d7f5d3SJohn Marino { 92*86d7f5d3SJohn Marino /* U and V have different sign. Need to compare them to determine 93*86d7f5d3SJohn Marino which operand to subtract from which. */ 94*86d7f5d3SJohn Marino 95*86d7f5d3SJohn Marino /* This test is right since ABS_USIZE >= ABS_VSIZE. */ 96*86d7f5d3SJohn Marino if (abs_usize != abs_vsize) 97*86d7f5d3SJohn Marino { 98*86d7f5d3SJohn Marino mpn_sub (wp, up, abs_usize, vp, abs_vsize); 99*86d7f5d3SJohn Marino wsize = abs_usize; 100*86d7f5d3SJohn Marino MPN_NORMALIZE (wp, wsize); 101*86d7f5d3SJohn Marino if (usize < 0) 102*86d7f5d3SJohn Marino wsize = -wsize; 103*86d7f5d3SJohn Marino } 104*86d7f5d3SJohn Marino else if (mpn_cmp (up, vp, abs_usize) < 0) 105*86d7f5d3SJohn Marino { 106*86d7f5d3SJohn Marino mpn_sub_n (wp, vp, up, abs_usize); 107*86d7f5d3SJohn Marino wsize = abs_usize; 108*86d7f5d3SJohn Marino MPN_NORMALIZE (wp, wsize); 109*86d7f5d3SJohn Marino if (usize >= 0) 110*86d7f5d3SJohn Marino wsize = -wsize; 111*86d7f5d3SJohn Marino } 112*86d7f5d3SJohn Marino else 113*86d7f5d3SJohn Marino { 114*86d7f5d3SJohn Marino mpn_sub_n (wp, up, vp, abs_usize); 115*86d7f5d3SJohn Marino wsize = abs_usize; 116*86d7f5d3SJohn Marino MPN_NORMALIZE (wp, wsize); 117*86d7f5d3SJohn Marino if (usize < 0) 118*86d7f5d3SJohn Marino wsize = -wsize; 119*86d7f5d3SJohn Marino } 120*86d7f5d3SJohn Marino } 121*86d7f5d3SJohn Marino else 122*86d7f5d3SJohn Marino { 123*86d7f5d3SJohn Marino /* U and V have same sign. Add them. */ 124*86d7f5d3SJohn Marino mp_limb_t cy_limb = mpn_add (wp, up, abs_usize, vp, abs_vsize); 125*86d7f5d3SJohn Marino wp[abs_usize] = cy_limb; 126*86d7f5d3SJohn Marino wsize = abs_usize + cy_limb; 127*86d7f5d3SJohn Marino if (usize < 0) 128*86d7f5d3SJohn Marino wsize = -wsize; 129*86d7f5d3SJohn Marino } 130*86d7f5d3SJohn Marino 131*86d7f5d3SJohn Marino w->_mp_size = wsize; 132*86d7f5d3SJohn Marino } 133