/ src / gmpy2_mul.c
gmpy2_mul.c
  1  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2   * gmpy2_mul.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.mul() and context.mul().
 28   */
 29  
 30  /* Multiply 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_MulWithType(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_mul(result->z, MPZ(x), MPZ(y));
 49              return (PyObject*)result;
 50          }
 51  
 52          if (IS_TYPE_PyInteger(ytype)) {
 53              int error;
 54              long temp = PyLong_AsLongAndOverflow(y, &error);
 55  
 56              if (!error) {
 57                   mpz_mul_si(result->z, MPZ(x), temp);
 58              }
 59              else {
 60                  mpz_set_PyIntOrLong(result->z, y);
 61                  mpz_mul(result->z, MPZ(x), result->z);
 62              }
 63              return (PyObject*)result;
 64          }
 65      }
 66  
 67      if (IS_TYPE_MPZANY(ytype)) {
 68          if (IS_TYPE_PyInteger(xtype)) {
 69              int error;
 70              long temp = PyLong_AsLongAndOverflow(x, &error);
 71  
 72              if (!error) {
 73                  mpz_mul_si(result->z, MPZ(y), temp);
 74              }
 75              else {
 76                  mpz_set_PyIntOrLong(result->z, x);
 77                  mpz_mul(result->z, result->z, MPZ(y));
 78              }
 79              return (PyObject*)result;
 80          }
 81      }
 82  
 83      if (IS_TYPE_INTEGER(xtype) && (IS_TYPE_INTEGER(ytype))) {
 84          MPZ_Object *tempx = NULL, *tempy = NULL;
 85  
 86          if (!(tempx = GMPy_MPZ_From_IntegerWithType(x, xtype, context)) ||
 87              !(tempy = GMPy_MPZ_From_IntegerWithType(y, ytype, context))) {
 88              /* LCOV_EXCL_START */
 89              Py_XDECREF((PyObject*)tempx);
 90              Py_XDECREF((PyObject*)tempy);
 91              Py_DECREF((PyObject*)result);
 92              return NULL;
 93              /* LCOV_EXCL_STOP */
 94          }
 95  
 96          mpz_mul(result->z, tempx->z, tempy->z);
 97          Py_DECREF((PyObject*)tempx);
 98          Py_DECREF((PyObject*)tempy);
 99          return (PyObject*)result;
100      }
101  
102      Py_DECREF((PyObject*)result);
103      TYPE_ERROR("mul() argument type not supported");
104      return NULL;
105  }
106  
107  static PyObject *
108  GMPy_Rational_MulWithType(PyObject *x, int xtype, PyObject *y, int ytype,
109                            CTXT_Object *context)
110  {
111      MPQ_Object *result = NULL;
112  
113      if (!(result = GMPy_MPQ_New(context))) {
114          /* LCOV_EXCL_START */
115          return NULL;
116          /* LCOV_EXCL_STOP */
117      }
118  
119      if (IS_TYPE_MPQ(xtype) && IS_TYPE_MPQ(ytype)) {
120          mpq_mul(result->q, MPQ(x), MPQ(y));
121          return (PyObject*)result;
122      }
123  
124      if (IS_TYPE_RATIONAL(xtype) && IS_TYPE_RATIONAL(ytype)) {
125          MPQ_Object *tempx = NULL, *tempy = NULL;
126  
127          if (!(tempx = GMPy_MPQ_From_RationalWithType(x, xtype, context)) ||
128              !(tempy = GMPy_MPQ_From_RationalWithType(y, ytype, context))) {
129              /* LCOV_EXCL_START */
130              Py_XDECREF((PyObject*)tempx);
131              Py_XDECREF((PyObject*)tempy);
132              Py_DECREF((PyObject*)result);
133              return NULL;
134              /* LCOV_EXCL_STOP */
135          }
136  
137          mpq_mul(result->q, tempx->q, tempy->q);
138          Py_DECREF((PyObject*)tempx);
139          Py_DECREF((PyObject*)tempy);
140          return (PyObject*)result;
141      }
142  
143      Py_DECREF((PyObject*)result);
144      TYPE_ERROR("mul() argument type not supported");
145      return NULL;
146  }
147  
148  static PyObject *
149  GMPy_Real_MulWithType(PyObject *x, int xtype, PyObject *y, int ytype,
150                        CTXT_Object *context)
151  {
152      MPFR_Object *result = NULL;
153  
154      CHECK_CONTEXT(context);
155  
156      if (!(result = GMPy_MPFR_New(0, context))) {
157          /* LCOV_EXCL_START */
158          return NULL;
159          /* LCOV_EXCL_STOP */
160      }
161  
162      if (IS_TYPE_MPFR(xtype) && IS_TYPE_MPFR(ytype)) {
163          mpfr_clear_flags();
164          result->rc = mpfr_mul(result->f, MPFR(x), MPFR(y), GET_MPFR_ROUND(context));
165          _GMPy_MPFR_Cleanup(&result, context);
166          return (PyObject*)result;
167      }
168  
169      if (IS_TYPE_REAL(xtype) && IS_TYPE_REAL(ytype)) {
170          MPFR_Object *tempx = NULL, *tempy = NULL;
171  
172          if (!(tempx = GMPy_MPFR_From_RealWithType(x, xtype, 1, context)) ||
173              !(tempy = GMPy_MPFR_From_RealWithType(y, ytype, 1, context))) {
174              /* LCOV_EXCL_START */
175              Py_XDECREF((PyObject*)tempx);
176              Py_XDECREF((PyObject*)tempy);
177              Py_DECREF((PyObject*)result);
178              return NULL;
179              /* LCOV_EXCL_STOP */
180          }
181  
182          mpfr_clear_flags();
183          result->rc = mpfr_mul(result->f, MPFR(tempx), MPFR(tempy), GET_MPFR_ROUND(context));
184          Py_DECREF((PyObject*)tempx);
185          Py_DECREF((PyObject*)tempy);
186          _GMPy_MPFR_Cleanup(&result, context);
187          return (PyObject*)result;
188      }
189  
190      Py_DECREF((PyObject*)result);
191      TYPE_ERROR("mul() argument type not supported");
192      return NULL;
193  }
194  
195  /* GMPy_Complex_Mul(x, y, context) returns x*y using the provided context. If
196   * an error occurs, NULL is returned and an exception is set. If either x or
197   * y can't be converted to an mpc, then Py_NotImplemented is returned. */
198  
199  static PyObject *
200  GMPy_Complex_MulWithType(PyObject *x, int xtype, PyObject *y, int ytype,
201                           CTXT_Object *context)
202  {
203      MPC_Object *result = NULL;
204  
205      CHECK_CONTEXT(context);
206  
207      if (!(result = GMPy_MPC_New(0, 0, context))) {
208          /* LCOV_EXCL_START */
209          return NULL;
210          /* LCOV_EXCL_STOP */
211      }
212  
213      if (IS_TYPE_MPC(xtype) && IS_TYPE_MPC(ytype)) {
214          result->rc = mpc_mul(result->c, MPC(x), MPC(y), GET_MPC_ROUND(context));
215          _GMPy_MPC_Cleanup(&result, context);
216          return (PyObject*)result;
217      }
218  
219      if (IS_TYPE_COMPLEX(xtype) && IS_TYPE_COMPLEX(ytype)) {
220          MPC_Object *tempx = NULL, *tempy = NULL;
221  
222          if (!(tempx = GMPy_MPC_From_ComplexWithType(x, xtype, 1, 1, context)) ||
223              !(tempy = GMPy_MPC_From_ComplexWithType(y, ytype, 1, 1, context))) {
224              /* LCOV_EXCL_START */
225              Py_XDECREF((PyObject*)tempx);
226              Py_XDECREF((PyObject*)tempy);
227              Py_DECREF((PyObject*)result);
228              return NULL;
229              /* LCOV_EXCL_STOP */
230          }
231          result->rc = mpc_mul(result->c, tempx->c, tempy->c, GET_MPC_ROUND(context));
232          Py_DECREF((PyObject*)tempx);
233          Py_DECREF((PyObject*)tempy);
234          _GMPy_MPC_Cleanup(&result, context);
235          return (PyObject*)result;
236      }
237  
238      Py_DECREF((PyObject*)result);
239      TYPE_ERROR("mul() argument type not supported");
240      return NULL;
241  }
242  
243  static PyObject *
244  GMPy_Number_Mul(PyObject *x, PyObject *y, CTXT_Object *context)
245  {
246      int xtype = GMPy_ObjectType(x);
247      int ytype = GMPy_ObjectType(y);
248      
249      if (IS_TYPE_INTEGER(xtype) && IS_TYPE_INTEGER(ytype))
250          return GMPy_Integer_MulWithType(x, xtype, y, ytype, context);
251  
252      if (IS_TYPE_RATIONAL(xtype) && IS_TYPE_RATIONAL(ytype))
253          return GMPy_Rational_MulWithType(x, xtype, y, ytype, context);
254  
255      if (IS_TYPE_REAL(xtype) && IS_TYPE_REAL(ytype))
256          return GMPy_Real_MulWithType(x, xtype, y, ytype, context);
257          
258      if (IS_TYPE_COMPLEX(xtype) && IS_TYPE_COMPLEX(ytype))
259          return GMPy_Complex_MulWithType(x, xtype, y, ytype, context);
260  
261      TYPE_ERROR("mul() argument type not supported");
262      return NULL;
263  }
264  
265  /* Implement all the slot methods here. */
266  
267  static PyObject *
268  GMPy_Number_Mul_Slot(PyObject *x, PyObject *y)
269  {
270      int xtype = GMPy_ObjectType(x);
271      int ytype = GMPy_ObjectType(y);
272      
273      if (IS_TYPE_INTEGER(xtype) && IS_TYPE_INTEGER(ytype))
274          return GMPy_Integer_MulWithType(x, xtype, y, ytype, NULL);
275  
276      if (IS_TYPE_RATIONAL(xtype) && IS_TYPE_RATIONAL(ytype))
277          return GMPy_Rational_MulWithType(x, xtype, y, ytype, NULL);
278  
279      if (IS_TYPE_REAL(xtype) && IS_TYPE_REAL(ytype))
280          return GMPy_Real_MulWithType(x, xtype, y, ytype, NULL);
281          
282      if (IS_TYPE_COMPLEX(xtype) && IS_TYPE_COMPLEX(ytype))
283          return GMPy_Complex_MulWithType(x, xtype, y, ytype, NULL);
284  
285      Py_RETURN_NOTIMPLEMENTED;
286  }
287  
288  /* Implement context.mul() and gmpy2.mul(). */
289  
290  PyDoc_STRVAR(GMPy_doc_function_mul,
291  "mul(x, y) -> number\n\n"
292  "Return x * y.");
293  
294  PyDoc_STRVAR(GMPy_doc_context_mul,
295  "context.mul(x, y) -> number\n\n"
296  "Return x * y.");
297  
298  static PyObject *
299  GMPy_Context_Mul(PyObject *self, PyObject *args)
300  {
301      CTXT_Object *context = NULL;
302  
303      if (PyTuple_GET_SIZE(args) != 2) {
304          TYPE_ERROR("mul() requires 2 arguments");
305          return NULL;
306      }
307  
308      if (self && CTXT_Check(self)) {
309          context = (CTXT_Object*)self;
310      }
311      else {
312          CHECK_CONTEXT(context);
313      }
314  
315      return GMPy_Number_Mul(PyTuple_GET_ITEM(args, 0),
316                             PyTuple_GET_ITEM(args, 1),
317                             context);
318  }
319