/ src / gmpy2_sub.c
gmpy2_sub.c
  1  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2   * gmpy2_sub.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.sub(), and context.sub().
 28   */
 29  
 30  /* Subtract two Integer objects (see gmpy2_convert.c). If an error occurs,
 31   * NULL is returned and an exception is set. If either x or y can't be
 32   * converted into an mpz, Py_NotImplemented is returned. */
 33  
 34  static PyObject *
 35  GMPy_Integer_SubWithType(PyObject *x, int xtype, PyObject *y, int ytype, 
 36                           CTXT_Object *context)
 37  {
 38      MPZ_Object *result = NULL;
 39  
 40      if (!(result = GMPy_MPZ_New(context))) {
 41          /* LCOV_EXCL_START */
 42          return NULL;
 43          /* LCOV_EXCL_STOP */
 44      }
 45  
 46      if (IS_TYPE_MPZANY(xtype)) {
 47          if (IS_TYPE_MPZANY(ytype)) {
 48              mpz_sub(result->z, MPZ(x), MPZ(y));
 49              return (PyObject*)result;
 50          }
 51          if (IS_TYPE_PyInteger(ytype)) {
 52              int error;
 53              long temp = PyLong_AsLongAndOverflow(y, &error);
 54  
 55              if (!error) {
 56                  if (temp >= 0) {
 57                      mpz_sub_ui(result->z, MPZ(x), temp);
 58                  }
 59                  else {
 60                      mpz_add_ui(result->z, MPZ(x), -temp);
 61                  }
 62              }
 63              else {
 64                  mpz_set_PyIntOrLong(result->z, y);
 65                  mpz_sub(result->z, MPZ(x), result->z);
 66              }
 67              return (PyObject*)result;
 68          }
 69      }
 70  
 71      if (IS_TYPE_MPZANY(ytype)) {
 72          if (IS_TYPE_PyInteger(xtype)) {
 73              int error;
 74              long temp = PyLong_AsLongAndOverflow(x, &error);
 75  
 76              if (!error) {
 77                  if (temp >= 0) {
 78                      mpz_ui_sub(result->z, temp, MPZ(y));
 79                  }
 80                  else {
 81                      mpz_add_ui(result->z, MPZ(y), -temp);
 82                      mpz_neg(result->z, result->z);
 83                  }
 84              }
 85              else {
 86                  mpz_set_PyIntOrLong(global.tempz, x);
 87                  mpz_sub(result->z, global.tempz, MPZ(y));
 88              }
 89              return (PyObject*)result;
 90          }
 91      }
 92  
 93      if (IS_TYPE_INTEGER(xtype) && IS_TYPE_INTEGER(ytype)) {
 94          MPZ_Object *tempx = NULL, *tempy = NULL;
 95  
 96          if (!(tempx = GMPy_MPZ_From_IntegerWithType(x, xtype, context)) ||
 97              !(tempy = GMPy_MPZ_From_IntegerWithType(y, ytype, context))) {
 98              /* LCOV_EXCL_START */
 99              Py_XDECREF((PyObject*)tempx);
100              Py_XDECREF((PyObject*)tempy);
101              Py_DECREF((PyObject*)result);
102              return NULL;
103              /* LCOV_EXCL_STOP */
104          }
105  
106          mpz_sub(result->z, tempx->z, tempy->z);
107          Py_DECREF((PyObject*)tempx);
108          Py_DECREF((PyObject*)tempy);
109          return (PyObject*)result;
110      }
111  
112      Py_DECREF((PyObject*)result);
113      TYPE_ERROR("sub() argument type not supported");
114      return NULL;
115  }
116  
117  /* Subtract two Rational objects (see gmpy2_convert.h). Returns None and
118   * raises TypeError if both objects are not valid rationals. Pympq_Sub_Rational
119   * is intended to be called from GMPy_Number_Sub(). */
120  
121  static PyObject *
122  GMPy_Rational_SubWithType(PyObject *x, int xtype, PyObject *y, int ytype,
123                            CTXT_Object *context)
124  {
125      MPQ_Object *result = NULL;
126  
127      if (!(result = GMPy_MPQ_New(context))) {
128          /* LCOV_EXCL_START */
129          return NULL;
130          /* LCOV_EXCL_STOP */
131      }
132  
133      if (IS_TYPE_MPQ(xtype) && IS_TYPE_MPQ(ytype)) {
134          mpq_sub(result->q, MPQ(x), MPQ(y));
135          return (PyObject*)result;
136      }
137  
138      if (IS_TYPE_RATIONAL(xtype) && IS_TYPE_RATIONAL(ytype)) {
139          MPQ_Object *tempx = NULL, *tempy = NULL;
140  
141          if (!(tempx = GMPy_MPQ_From_RationalWithType(x, xtype, context)) ||
142              !(tempy = GMPy_MPQ_From_RationalWithType(y, ytype, context))) {
143              /* LCOV_EXCL_START */
144              Py_XDECREF((PyObject*)tempx);
145              Py_XDECREF((PyObject*)tempy);
146              Py_DECREF((PyObject*)result);
147              return NULL;
148              /* LCOV_EXCL_STOP */
149          }
150  
151          mpq_sub(result->q, tempx->q, tempy->q);
152          Py_DECREF((PyObject*)tempx);
153          Py_DECREF((PyObject*)tempy);
154          return (PyObject*)result;
155      }
156  
157      /* LCOV_EXCL_START */
158      Py_DECREF((PyObject*)result);
159      TYPE_ERROR("sub() argument type not supported");
160      return NULL;
161      /* LCOV_EXCL_STOP */
162  }
163  
164  /*   GMPy_Real_Sub(x, y, context) returns x-y using the provided context. If
165   *   provided context is NULL, then the current context is used. If an error
166   *   occurs, NULL is returned and an exception is set. If either x or y can't
167   *   be converted to an mpfr, then Py_NotImplemented is returned.
168   *   GMPy_Real_Sub() will not try to promote the result to a different type
169   *   (i.e. mpc).
170  */
171  
172  static PyObject *
173  GMPy_Real_SubWithType(PyObject *x, int xtype, PyObject *y, int ytype,
174                        CTXT_Object *context)
175  {
176      MPFR_Object *result = NULL;
177  
178      CHECK_CONTEXT(context);
179  
180      if (!(result = GMPy_MPFR_New(0, context))) {
181          /* LCOV_EXCL_START */
182          return NULL;
183          /* LCOV_EXCL_STOP */
184      }
185  
186      if (IS_TYPE_MPFR(xtype) && IS_TYPE_MPFR(ytype)) {
187          mpfr_clear_flags();
188          result->rc = mpfr_sub(result->f, MPFR(x), MPFR(y), GET_MPFR_ROUND(context));
189          _GMPy_MPFR_Cleanup(&result, context);
190          return (PyObject*)result;
191      }
192  
193      if (IS_TYPE_REAL(xtype) && IS_TYPE_REAL(ytype)) {
194          MPFR_Object *tempx = NULL, *tempy = NULL;
195  
196          if (!(tempx = GMPy_MPFR_From_RealWithType(x, xtype, 1, context)) ||
197              !(tempy = GMPy_MPFR_From_RealWithType(y, ytype, 1, context))) {
198              /* LCOV_EXCL_START */
199              Py_XDECREF((PyObject*)tempx);
200              Py_XDECREF((PyObject*)tempy);
201              Py_DECREF((PyObject*)result);
202              return NULL;
203              /* LCOV_EXCL_STOP */
204          }
205  
206          mpfr_clear_flags();
207  
208          result->rc = mpfr_sub(result->f, MPFR(tempx), MPFR(tempy), GET_MPFR_ROUND(context));
209          Py_DECREF((PyObject*)tempx);
210          Py_DECREF((PyObject*)tempy);
211          goto done;
212      }
213  
214      /* LCOV_EXCL_START */
215      Py_DECREF((PyObject*)result);
216      TYPE_ERROR("sub() argument type not supported");
217      return NULL;
218      /* LCOV_EXCL_STOP */
219  
220    done:
221      _GMPy_MPFR_Cleanup(&result, context);
222      return (PyObject*)result;
223  }
224  
225  /* GMPy_Complex_Sub(x, y, context) returns x-y using the provided context. If
226   * context is NULL, then the current context is used. If an error occurs, NULL
227   * is returned and an exception is set. If either x or y can't be converted to
228   * an mpc, then Py_NotImplemented is returned. */
229  
230  static PyObject *
231  GMPy_Complex_SubWithType(PyObject *x, int xtype, PyObject *y, int ytype,
232                           CTXT_Object *context)
233  {
234      MPC_Object *result = NULL;
235  
236      CHECK_CONTEXT(context);
237  
238      if (!(result = GMPy_MPC_New(0, 0, context))) {
239          /* LCOV_EXCL_START */
240          return NULL;
241          /* LCOV_EXCL_STOP */
242      }
243  
244      if (IS_TYPE_MPC(xtype) && IS_TYPE_MPC(ytype)) {
245          result->rc = mpc_sub(result->c, MPC(x), MPC(y), GET_MPC_ROUND(context));
246          _GMPy_MPC_Cleanup(&result, context);
247          return (PyObject*)result;
248      }
249  
250      if (IS_TYPE_COMPLEX(xtype) && IS_TYPE_COMPLEX(ytype)) {
251          MPC_Object *tempx = NULL, *tempy = NULL;
252  
253          if (!(tempx = GMPy_MPC_From_ComplexWithType(x, xtype, 1, 1, context)) ||
254              !(tempy = GMPy_MPC_From_ComplexWithType(y, ytype, 1, 1, context))) {
255              /* LCOV_EXCL_START */
256              Py_XDECREF((PyObject*)tempx);
257              Py_XDECREF((PyObject*)tempy);
258              Py_DECREF((PyObject*)result);
259              return NULL;
260              /* LCOV_EXCL_STOP */
261          }
262  
263          result->rc = mpc_sub(result->c, tempx->c, tempy->c, GET_MPC_ROUND(context));
264          Py_DECREF((PyObject*)tempx);
265          Py_DECREF((PyObject*)tempy);
266          _GMPy_MPC_Cleanup(&result, context);
267          return (PyObject*)result;
268      }
269  
270      /* LCOV_EXCL_START */
271      Py_DECREF((PyObject*)result);
272      TYPE_ERROR("sub() argument type not supported");
273      return NULL;
274      /* LCOV_EXCL_STOP */
275  }
276  
277  static PyObject *
278  GMPy_Number_Sub(PyObject *x, PyObject *y, CTXT_Object *context)
279  {
280      int xtype = GMPy_ObjectType(x);
281      int ytype = GMPy_ObjectType(y);
282      
283      if (IS_TYPE_INTEGER(xtype) && IS_TYPE_INTEGER(ytype))
284          return GMPy_Integer_SubWithType(x, xtype, y, ytype, context);
285  
286      if (IS_TYPE_RATIONAL(xtype) && IS_TYPE_RATIONAL(ytype))
287          return GMPy_Rational_SubWithType(x, xtype, y, ytype, context);
288  
289      if (IS_TYPE_REAL(xtype) && IS_TYPE_REAL(ytype))
290          return GMPy_Real_SubWithType(x, xtype, y, ytype, context);
291          
292      if (IS_TYPE_COMPLEX(xtype) && IS_TYPE_COMPLEX(ytype))
293          return GMPy_Complex_SubWithType(x, xtype, y, ytype, context);
294  
295      TYPE_ERROR("sub() argument type not supported");
296      return NULL;
297  }
298  
299  /* Implement all the slot methods here. */
300  
301  static PyObject *
302  GMPy_Number_Sub_Slot(PyObject *x, PyObject *y)
303  {
304      int xtype = GMPy_ObjectType(x);
305      int ytype = GMPy_ObjectType(y);
306      
307      if (IS_TYPE_INTEGER(xtype) && IS_TYPE_INTEGER(ytype))
308          return GMPy_Integer_SubWithType(x, xtype, y, ytype, NULL);
309  
310      if (IS_TYPE_RATIONAL(xtype) && IS_TYPE_RATIONAL(ytype))
311          return GMPy_Rational_SubWithType(x, xtype, y, ytype, NULL);
312  
313      if (IS_TYPE_REAL(xtype) && IS_TYPE_REAL(ytype))
314          return GMPy_Real_SubWithType(x, xtype, y, ytype, NULL);
315          
316      if (IS_TYPE_COMPLEX(xtype) && IS_TYPE_COMPLEX(ytype))
317          return GMPy_Complex_SubWithType(x, xtype, y, ytype, NULL);
318  
319      Py_RETURN_NOTIMPLEMENTED;
320  }
321  
322  /* Implement context.sub() and gmpy2.sub(). */
323  
324  PyDoc_STRVAR(GMPy_doc_sub,
325  "sub(x, y) -> number\n\n"
326  "Return x - y.");
327  
328  PyDoc_STRVAR(GMPy_doc_context_sub,
329  "context.sub(x, y) -> number\n\n"
330  "Return x - y.");
331  
332  static PyObject *
333  GMPy_Context_Sub(PyObject *self, PyObject *args)
334  {
335      CTXT_Object *context = NULL;
336  
337      if (PyTuple_GET_SIZE(args) != 2) {
338          TYPE_ERROR("sub() requires 2 arguments");
339          return NULL;
340      }
341  
342      if (self && CTXT_Check(self)) {
343          context = (CTXT_Object*)self;
344      }
345      else {
346          CHECK_CONTEXT(context);
347      }
348  
349      return GMPy_Number_Sub(PyTuple_GET_ITEM(args, 0),
350                             PyTuple_GET_ITEM(args, 1),
351                             context);
352  }
353