/ src / gmpy2_add.c
gmpy2_add.c
  1  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2   * gmpy2_add.c                                                             *
  3   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  4   * Python interface to the GMP or MPIR, MPFR, and MPC multiple precision   *
  5   * libraries.                                                              *
  6   *                                                                         *
  7   * Copyright 2000 - 2009 Alex Martelli                                     *
  8   *                                                                         *
  9   * Copyright 2008 - 2021 Case Van Horsen                                   *
 10   *                                                                         *
 11   * This file is part of GMPY2.                                             *
 12   *                                                                         *
 13   * GMPY2 is free software: you can redistribute it and/or modify it under  *
 14   * the terms of the GNU Lesser General Public License as published by the  *
 15   * Free Software Foundation, either version 3 of the License, or (at your  *
 16   * option) any later version.                                              *
 17   *                                                                         *
 18   * GMPY2 is distributed in the hope that it will be useful, but WITHOUT    *
 19   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or   *
 20   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public    *
 21   * License for more details.                                               *
 22   *                                                                         *
 23   * You should have received a copy of the GNU Lesser General Public        *
 24   * License along with GMPY2; if not, see <http://www.gnu.org/licenses/>    *
 25   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 26  
 27  /* This file implements the + operator, gmpy2.add(), and context.add().
 28   */
 29  
 30  /* Add two Integer objects (see gmpy2_convert.h). If an error occurs, NULL
 31   * is returned and an exception is set. If either x or y can't be converted
 32   * into an mpz, a type error is returned.
 33   */
 34  
 35  static PyObject *
 36  GMPy_Integer_AddWithType(PyObject *x, int xtype, PyObject *y, int ytype, 
 37                           CTXT_Object *context)
 38  {
 39      MPZ_Object *result = NULL;
 40  
 41      if (!(result = GMPy_MPZ_New(context))) {
 42          /* LCOV_EXCL_START */
 43          return NULL;
 44          /* LCOV_EXCL_STOP */
 45      }
 46  
 47      if (IS_TYPE_MPZANY(xtype)) {
 48          if (IS_TYPE_MPZANY(ytype)) {
 49              mpz_add(result->z, MPZ(x), MPZ(y));
 50              return (PyObject*)result;
 51          }
 52  
 53          if (IS_TYPE_PyInteger(ytype)) {
 54              int error;
 55              long temp = PyLong_AsLongAndOverflow(y, &error);
 56  
 57              if (!error) {
 58                  if (temp >= 0) {
 59                      mpz_add_ui(result->z, MPZ(x), temp);
 60                  }
 61                  else {
 62                      mpz_sub_ui(result->z, MPZ(x), -temp);
 63                  }
 64              }
 65              else {
 66                  mpz_set_PyIntOrLong(result->z, y);
 67                  mpz_add(result->z, MPZ(x), result->z);
 68              }
 69              return (PyObject*)result;
 70          }
 71      }
 72  
 73      if (IS_TYPE_MPZANY(ytype)) {
 74          if (IS_TYPE_PyInteger(xtype)) {
 75              int error;
 76              long temp = PyLong_AsLongAndOverflow(x, &error);
 77  
 78              if (!error) {
 79                  if (temp >= 0) {
 80                      mpz_add_ui(result->z, MPZ(y), temp);
 81                  }
 82                  else {
 83                      mpz_sub_ui(result->z, MPZ(y), -temp);
 84                  }
 85              }
 86              else {
 87                  mpz_set_PyIntOrLong(result->z, x);
 88                  mpz_add(result->z, result->z, MPZ(y));
 89              }
 90              return (PyObject*)result;
 91          }
 92      }
 93  
 94      if (IS_TYPE_INTEGER(xtype) && (IS_TYPE_INTEGER(ytype))) {
 95          MPZ_Object *tempx = NULL, *tempy = NULL;
 96  
 97          if (!(tempx = GMPy_MPZ_From_IntegerWithType(x, xtype, context)) ||
 98              !(tempy = GMPy_MPZ_From_IntegerWithType(y, ytype, context))) {
 99              /* LCOV_EXCL_START */
100              Py_XDECREF((PyObject*)tempx);
101              Py_XDECREF((PyObject*)tempy);
102              Py_DECREF((PyObject*)result);
103              return NULL;
104              /* LCOV_EXCL_STOP */
105          }
106  
107          mpz_add(result->z, tempx->z, tempy->z);
108          Py_DECREF((PyObject*)tempx);
109          Py_DECREF((PyObject*)tempy);
110          return (PyObject*)result;
111      }
112  
113      Py_DECREF((PyObject*)result);
114      TYPE_ERROR("add() argument type not supported");
115      return NULL;
116  }
117  
118  static PyObject *
119  GMPy_Rational_AddWithType(PyObject *x, int xtype, PyObject *y, int ytype,
120                            CTXT_Object *context)
121  {
122      MPQ_Object *result = NULL;
123  
124      if (!(result = GMPy_MPQ_New(context))) {
125          /* LCOV_EXCL_START */
126          return NULL;
127          /* LCOV_EXCL_STOP */
128      }
129  
130      if (IS_TYPE_MPQ(xtype) && IS_TYPE_MPQ(ytype)) {
131          mpq_add(result->q, MPQ(x), MPQ(y));
132          return (PyObject*)result;
133      }
134  
135      if (IS_TYPE_RATIONAL(xtype) && IS_TYPE_RATIONAL(ytype)) {
136          MPQ_Object *tempx = NULL, *tempy = NULL;
137  
138          if (!(tempx = GMPy_MPQ_From_RationalWithType(x, xtype, context)) ||
139              !(tempy = GMPy_MPQ_From_RationalWithType(y, ytype, context))) {
140              /* LCOV_EXCL_START */
141              Py_XDECREF((PyObject*)tempx);
142              Py_XDECREF((PyObject*)tempy);
143              Py_DECREF((PyObject*)result);
144              return NULL;
145              /* LCOV_EXCL_STOP */
146          }
147  
148          mpq_add(result->q, tempx->q, tempy->q);
149          Py_DECREF((PyObject*)tempx);
150          Py_DECREF((PyObject*)tempy);
151          return (PyObject*)result;
152      }
153  
154      Py_DECREF((PyObject*)result);
155      TYPE_ERROR("add() argument type not supported");
156      return NULL;
157  }
158  
159  /* Addition can be performed by the equivalent of mpfr.__add__ or by
160   * gmpy2.add().
161   *
162   *   GMPy_Real_Add(x, y, context) returns x+y using the provided context. If
163   *   provided context is NULL, then the current context is used. If an error
164   *   occurs, NULL is returned and an exception is set. If either x or y can't
165   *   be converted to an mpfr, then Py_NotImplemented is returned.
166   *    GMPy_Real_Add() will not try to promote the result to a different type
167   *   (i.e. mpc).
168   */
169  
170  /* Attempt to add two numbers and return an mpfr. The code path is optimized by
171   * checking for mpfr objects first. Returns Py_NotImplemented if both objects
172   * are not valid reals.  */
173  
174  static PyObject *
175  GMPy_Real_AddWithType(PyObject *x, int xtype, PyObject *y, int ytype,
176                        CTXT_Object *context)
177  {
178      MPFR_Object *result = NULL;
179  
180      CHECK_CONTEXT(context);
181  
182      if (!(result = GMPy_MPFR_New(0, context))) {
183          /* LCOV_EXCL_START */
184          return NULL;
185          /* LCOV_EXCL_STOP */
186      }
187  
188      if (IS_TYPE_MPFR(xtype) && IS_TYPE_MPFR(ytype)) {
189          mpfr_clear_flags();
190          result->rc = mpfr_add(result->f, MPFR(x), MPFR(y), GET_MPFR_ROUND(context));
191          _GMPy_MPFR_Cleanup(&result, context);
192          return (PyObject*)result;
193      }
194      
195      if (IS_TYPE_REAL(xtype) && IS_TYPE_REAL(ytype)) {
196          MPFR_Object *tempx = NULL, *tempy = NULL;
197  
198          if (!(tempx = GMPy_MPFR_From_RealWithType(x, xtype, 1, context)) ||
199              !(tempy = GMPy_MPFR_From_RealWithType(y, ytype, 1, context))) {
200              /* LCOV_EXCL_START */
201              Py_XDECREF((PyObject*)tempx);
202              Py_XDECREF((PyObject*)tempy);
203              Py_DECREF((PyObject*)result);
204              return NULL;
205              /* LCOV_EXCL_STOP */
206          }
207  
208          mpfr_clear_flags();
209          result->rc = mpfr_add(result->f, MPFR(tempx), MPFR(tempy), GET_MPFR_ROUND(context));
210          Py_DECREF((PyObject*)tempx);
211          Py_DECREF((PyObject*)tempy);
212          _GMPy_MPFR_Cleanup(&result, context);
213          return (PyObject*)result;
214      }
215  
216      Py_DECREF((PyObject*)result);
217      TYPE_ERROR("add() argument type not supported");
218      return NULL;
219  }
220  
221  /* GMPy_Complex_Add(x, y, context) returns x+y using the provided context. If
222   * context is NULL, then the current context is used. If an error occurs, NULL
223   * is returned and an exception is set. If either x or y can't be converted to
224   * an mpc, then Py_NotImplemented is returned. */
225  
226  
227  static PyObject *
228  GMPy_Complex_AddWithType(PyObject *x, int xtype, PyObject *y, int ytype,
229                           CTXT_Object *context)
230  {
231      MPC_Object *result = NULL;
232  
233      CHECK_CONTEXT(context);
234  
235      if (!(result = GMPy_MPC_New(0, 0, context))) {
236          /* LCOV_EXCL_START */
237          return NULL;
238          /* LCOV_EXCL_STOP */
239      }
240  
241      if (IS_TYPE_MPC(xtype) && IS_TYPE_MPC(ytype)) {
242          result->rc = mpc_add(result->c, MPC(x), MPC(y), GET_MPC_ROUND(context));
243          _GMPy_MPC_Cleanup(&result, context);
244          return (PyObject*)result;
245      }
246  
247      if (IS_TYPE_COMPLEX(xtype) && IS_TYPE_COMPLEX(ytype)) {
248          MPC_Object *tempx = NULL, *tempy = NULL;
249  
250          if (!(tempx = GMPy_MPC_From_ComplexWithType(x, xtype, 1, 1, context)) ||
251              !(tempy = GMPy_MPC_From_ComplexWithType(y, ytype, 1, 1, context))) {
252              /* LCOV_EXCL_START */
253              Py_XDECREF((PyObject*)tempx);
254              Py_XDECREF((PyObject*)tempy);
255              Py_DECREF((PyObject*)result);
256              return NULL;
257              /* LCOV_EXCL_STOP */
258          }
259          result->rc = mpc_add(result->c, tempx->c, tempy->c, GET_MPC_ROUND(context));
260          Py_DECREF((PyObject*)tempx);
261          Py_DECREF((PyObject*)tempy);
262          _GMPy_MPC_Cleanup(&result, context);
263          return (PyObject*)result;
264      }
265  
266      Py_DECREF((PyObject*)result);
267      TYPE_ERROR("add() argument type not supported");
268      return NULL;
269  }
270  
271  /* Implement all the slot methods here. */
272  
273  static PyObject *
274  GMPy_Number_Add_Slot(PyObject *x, PyObject *y)
275  {
276      int xtype = GMPy_ObjectType(x);
277      int ytype = GMPy_ObjectType(y);
278      
279      if (IS_TYPE_INTEGER(xtype) && IS_TYPE_INTEGER(ytype))
280          return GMPy_Integer_AddWithType(x, xtype, y, ytype, NULL);
281  
282      if (IS_TYPE_RATIONAL(xtype) && IS_TYPE_RATIONAL(ytype))
283          return GMPy_Rational_AddWithType(x, xtype, y, ytype, NULL);
284  
285      if (IS_TYPE_REAL(xtype) && IS_TYPE_REAL(ytype))
286          return GMPy_Real_AddWithType(x, xtype, y, ytype, NULL);
287          
288      if (IS_TYPE_COMPLEX(xtype) && IS_TYPE_COMPLEX(ytype))
289          return GMPy_Complex_AddWithType(x, xtype, y, ytype, NULL);
290  
291      Py_RETURN_NOTIMPLEMENTED;
292  }
293  
294  /* Implement context.add() and gmpy2.add(). */
295  
296  PyDoc_STRVAR(GMPy_doc_function_add,
297  "add(x, y) -> number\n\n"
298  "Return x + y.");
299  
300  static PyObject *
301  GMPy_Number_Add(PyObject *x, PyObject *y, CTXT_Object *context)
302  {
303      int xtype = GMPy_ObjectType(x);
304      int ytype = GMPy_ObjectType(y);
305      
306      if (IS_TYPE_INTEGER(xtype) && IS_TYPE_INTEGER(ytype))
307          return GMPy_Integer_AddWithType(x, xtype, y, ytype, context);
308  
309      if (IS_TYPE_RATIONAL(xtype) && IS_TYPE_RATIONAL(ytype))
310          return GMPy_Rational_AddWithType(x, xtype, y, ytype, context);
311  
312      if (IS_TYPE_REAL(xtype) && IS_TYPE_REAL(ytype))
313          return GMPy_Real_AddWithType(x, xtype, y, ytype, context);
314          
315      if (IS_TYPE_COMPLEX(xtype) && IS_TYPE_COMPLEX(ytype))
316          return GMPy_Complex_AddWithType(x, xtype, y, ytype, context);
317  
318      TYPE_ERROR("add() argument type not supported");
319      return NULL;
320  }
321  
322  PyDoc_STRVAR(GMPy_doc_context_add,
323  "context.add(x, y) -> number\n\n"
324  "Return x + y.");
325  
326  static PyObject *
327  GMPy_Context_Add(PyObject *self, PyObject *args)
328  {
329      CTXT_Object *context = NULL;
330  
331      if (PyTuple_GET_SIZE(args) != 2) {
332          TYPE_ERROR("add() requires 2 arguments");
333          return NULL;
334      }
335  
336      if (self && CTXT_Check(self)) {
337          context = (CTXT_Object*)self;
338      }
339      else {
340          CHECK_CONTEXT(context);
341      }
342  
343      return GMPy_Number_Add(PyTuple_GET_ITEM(args, 0),
344                             PyTuple_GET_ITEM(args, 1),
345                             context);
346  }
347