1/* mpz_add, mpz_sub -- add or subtract integers. 2 3Copyright 1991, 1993, 1994, 1996, 2000, 2001 Free Software Foundation, Inc. 4 5This file is part of the GNU MP Library. 6 7The GNU MP Library is free software; you can redistribute it and/or modify 8it under the terms of the GNU Lesser General Public License as published by 9the Free Software Foundation; either version 3 of the License, or (at your 10option) any later version. 11 12The GNU MP Library is distributed in the hope that it will be useful, but 13WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15License for more details. 16 17You should have received a copy of the GNU Lesser General Public License 18along 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 52Error, need OPERATION_add or OPERATION_sub 53#endif 54 55 56void 57FUNCTION (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