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