/ src / gmpy2_mpz_divmod.c
gmpy2_mpz_divmod.c
  1  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2   * gmpy2_mpz_divmod.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  
 28  /* This file contains functions related to division and remainder. */
 29  
 30  /*
 31   **************************************************************************
 32   * Ceiling division and remainder.
 33   **************************************************************************
 34   */
 35  
 36  PyDoc_STRVAR(doc_c_divmod,
 37  "c_divmod(x, y) -> (quotient, remainder)\n\n"
 38  "Return the quotient and remainder of x divided by y. The quotient\n"
 39  "is rounded towards +Inf (ceiling rounding) and the remainder will\n"
 40  "have the opposite sign of y. x and y must be integers.");
 41  
 42  static PyObject *
 43  GMPy_MPZ_c_divmod(PyObject *self, PyObject *args)
 44  {
 45      PyObject *result = NULL;
 46      MPZ_Object *q = NULL, *r = NULL, *tempx = NULL, *tempy = NULL;
 47  
 48      if (PyTuple_GET_SIZE(args) != 2) {
 49          TYPE_ERROR("c_divmod() requires 'mpz','mpz' arguments");
 50          return NULL;
 51      }
 52  
 53      if (!(tempx = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 0), NULL)) ||
 54          !(tempy = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 1), NULL)) ||
 55          !(q = GMPy_MPZ_New(NULL)) ||
 56          !(r = GMPy_MPZ_New(NULL)) ||
 57          !(result = PyTuple_New(2))) {
 58  
 59          goto err;
 60      }
 61  
 62      if (mpz_sgn(tempy->z) == 0) {
 63          ZERO_ERROR("c_divmod() division by 0");
 64          goto err;
 65      }
 66  
 67      mpz_cdiv_qr(q->z, r->z, tempx->z, tempy->z);
 68  
 69      Py_DECREF((PyObject*)tempx);
 70      Py_DECREF((PyObject*)tempy);
 71      PyTuple_SET_ITEM(result, 0, (PyObject*)q);
 72      PyTuple_SET_ITEM(result, 1, (PyObject*)r);
 73      return result;
 74  
 75    err:
 76      Py_XDECREF(result);
 77      Py_XDECREF((PyObject*)tempx);
 78      Py_XDECREF((PyObject*)tempy);
 79      Py_XDECREF((PyObject*)q);
 80      Py_XDECREF((PyObject*)r);
 81      return NULL;
 82  }
 83  
 84  PyDoc_STRVAR(doc_c_div,
 85  "c_div(x, y) -> quotient\n\n"
 86  "Return the quotient of x divided by y. The quotient is rounded\n"
 87  "towards +Inf (ceiling rounding). x and y must be integers.");
 88  
 89  static PyObject *
 90  GMPy_MPZ_c_div(PyObject *self, PyObject *args)
 91  {
 92      MPZ_Object *q = NULL, *tempx = NULL, *tempy = NULL;
 93  
 94      if (PyTuple_GET_SIZE(args) != 2) {
 95          TYPE_ERROR("c_div() requires 'mpz','mpz' arguments");
 96          return NULL;
 97      }
 98  
 99      if (!(tempx = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 0), NULL)) ||
100          !(tempy = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 1), NULL)) ||
101          !(q = GMPy_MPZ_New(NULL))) {
102  
103          goto err;
104      }
105  
106      if (mpz_sgn(tempy->z) == 0) {
107          ZERO_ERROR("c_div() division by 0");
108          goto err;
109      }
110  
111      mpz_cdiv_q(q->z, tempx->z, tempy->z);
112  
113      Py_DECREF((PyObject*)tempx);
114      Py_DECREF((PyObject*)tempy);
115      return (PyObject*)q;
116  
117    err:
118      Py_XDECREF((PyObject*)tempx);
119      Py_XDECREF((PyObject*)tempy);
120      Py_XDECREF((PyObject*)q);
121      return NULL;
122  }
123  
124  PyDoc_STRVAR(doc_c_mod,
125  "c_mod(x, y) -> remainder\n\n"
126  "Return the remainder of x divided by y. The remainder will have\n"
127  "the opposite sign of y. x and y must be integers.");
128  
129  static PyObject *
130  GMPy_MPZ_c_mod(PyObject *self, PyObject *args)
131  {
132      MPZ_Object *r = NULL, *tempx = NULL, *tempy = NULL;
133  
134      if (PyTuple_GET_SIZE(args) != 2) {
135          TYPE_ERROR("c_mod() requires 'mpz','mpz' arguments");
136          return NULL;
137      }
138  
139      if (!(tempx = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 0), NULL)) ||
140          !(tempy = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 1), NULL)) ||
141          !(r = GMPy_MPZ_New(NULL))) {
142  
143          goto err;
144      }
145  
146      if (mpz_sgn(tempy->z) == 0) {
147          ZERO_ERROR("c_mod() division by 0");
148          goto err;
149      }
150  
151      mpz_cdiv_r(r->z, tempx->z, tempy->z);
152  
153      Py_DECREF((PyObject*)tempx);
154      Py_DECREF((PyObject*)tempy);
155      return (PyObject*)r;
156  
157    err:
158      Py_XDECREF((PyObject*)tempx);
159      Py_XDECREF((PyObject*)tempy);
160      Py_XDECREF((PyObject*)r);
161      return NULL;
162  }
163  
164  /*
165   **************************************************************************
166   * Floor division and remainder.
167   **************************************************************************
168   */
169  
170  PyDoc_STRVAR(doc_f_divmod,
171  "f_divmod(x, y) -> (quotient, remainder)\n\n"
172  "Return the quotient and remainder of x divided by y. The quotient\n"
173  "is rounded towards -Inf (floor rounding) and the remainder will\n"
174  "have the same sign as y. x and y must be integers.");
175  
176  static PyObject *
177  GMPy_MPZ_f_divmod(PyObject *self, PyObject *args)
178  {
179      PyObject *result = NULL;
180      MPZ_Object *q = NULL, *r = NULL, *tempx = NULL, *tempy = NULL;
181  
182      if (PyTuple_GET_SIZE(args) != 2) {
183          TYPE_ERROR("f_divmod() requires 'mpz','mpz' arguments");
184          return NULL;
185      }
186  
187      if (!(tempx = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 0), NULL)) ||
188          !(tempy = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 1), NULL)) ||
189          !(q = GMPy_MPZ_New(NULL)) ||
190          !(r = GMPy_MPZ_New(NULL)) ||
191          !(result = PyTuple_New(2))) {
192  
193          goto err;
194      }
195  
196      if (mpz_sgn(tempy->z) == 0) {
197          ZERO_ERROR("f_divmod() division by 0");
198          goto err;
199      }
200  
201      mpz_fdiv_qr(q->z, r->z, tempx->z, tempy->z);
202  
203      Py_DECREF((PyObject*)tempx);
204      Py_DECREF((PyObject*)tempy);
205      PyTuple_SET_ITEM(result, 0, (PyObject*)q);
206      PyTuple_SET_ITEM(result, 1, (PyObject*)r);
207      return result;
208  
209    err:
210      Py_XDECREF(result);
211      Py_XDECREF((PyObject*)tempx);
212      Py_XDECREF((PyObject*)tempy);
213      Py_XDECREF((PyObject*)q);
214      Py_XDECREF((PyObject*)r);
215      return NULL;
216  }
217  
218  PyDoc_STRVAR(doc_f_div,
219  "f_div(x, y) -> quotient\n\n"
220  "Return the quotient of x divided by y. The quotient is rounded\n"
221  "towards -Inf (floor rounding). x and y must be integers.");
222  
223  static PyObject *
224  GMPy_MPZ_f_div(PyObject *self, PyObject *args)
225  {
226      MPZ_Object *q = NULL, *tempx = NULL, *tempy = NULL;
227  
228      if(PyTuple_GET_SIZE(args) != 2) {
229          TYPE_ERROR("f_div() requires 'mpz','mpz' arguments");
230          return NULL;
231      }
232  
233      if (!(tempx = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 0), NULL)) ||
234          !(tempy = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 1), NULL)) ||
235          !(q = GMPy_MPZ_New(NULL))) {
236  
237          goto err;
238      }
239  
240      if (mpz_sgn(tempy->z) == 0) {
241          ZERO_ERROR("f_div() division by 0");
242          goto err;
243      }
244  
245      mpz_fdiv_q(q->z, tempx->z, tempy->z);
246  
247      Py_DECREF((PyObject*)tempx);
248      Py_DECREF((PyObject*)tempy);
249      return (PyObject*)q;
250  
251    err:
252      Py_XDECREF((PyObject*)tempx);
253      Py_XDECREF((PyObject*)tempy);
254      Py_XDECREF((PyObject*)q);
255      return NULL;
256  }
257  
258  PyDoc_STRVAR(doc_f_mod,
259  "f_mod(x, y) -> remainder\n\n"
260  "Return the remainder of x divided by y. The remainder will have\n"
261  "the same sign as y. x and y must be integers.");
262  
263  static PyObject *
264  GMPy_MPZ_f_mod(PyObject *self, PyObject *args)
265  {
266      MPZ_Object *r = NULL, *tempx = NULL, *tempy = NULL;
267  
268      if (PyTuple_GET_SIZE(args) != 2) {
269          TYPE_ERROR("f_mod() requires 'mpz','mpz' arguments");
270          return NULL;
271      }
272  
273      if (!(tempx = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 0), NULL)) ||
274          !(tempy = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 1), NULL)) ||
275          !(r = GMPy_MPZ_New(NULL))) {
276  
277          goto err;
278      }
279  
280      if (mpz_sgn(tempy->z) == 0) {
281          ZERO_ERROR("f_mod() division by 0");
282          goto err;
283      }
284  
285      mpz_fdiv_r(r->z, tempx->z, tempy->z);
286  
287      Py_DECREF((PyObject*)tempx);
288      Py_DECREF((PyObject*)tempy);
289      return (PyObject*)r;
290  
291    err:
292      Py_XDECREF((PyObject*)tempx);
293      Py_XDECREF((PyObject*)tempy);
294      Py_XDECREF((PyObject*)r);
295      return NULL;
296  }
297  
298  /*
299   **************************************************************************
300   * Truncating division and remainder.
301   **************************************************************************
302   */
303  
304  PyDoc_STRVAR(doc_t_divmod,
305  "t_divmod(x, y) -> (quotient, remainder)\n\n"
306  "Return the quotient and remainder of x divided by y. The quotient\n"
307  "is rounded towards zero (truncation) and the remainder will have\n"
308  "the same sign as x. x and y must be integers.");
309  
310  static PyObject *
311  GMPy_MPZ_t_divmod(PyObject *self, PyObject *args)
312  {
313      PyObject *result = NULL;
314      MPZ_Object *q = NULL, *r = NULL, *tempx = NULL, *tempy = NULL;
315  
316      if (PyTuple_GET_SIZE(args) != 2) {
317          TYPE_ERROR("t_divmod() requires 'mpz','mpz' arguments");
318          return NULL;
319      }
320  
321      if (!(tempx = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 0), NULL)) ||
322          !(tempy = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 1), NULL)) ||
323          !(q = GMPy_MPZ_New(NULL)) ||
324          !(r = GMPy_MPZ_New(NULL)) ||
325          !(result = PyTuple_New(2))) {
326  
327          goto err;
328      }
329  
330      if (mpz_sgn(tempy->z) == 0) {
331          ZERO_ERROR("t_divmod() division by 0");
332          goto err;
333      }
334  
335      mpz_tdiv_qr(q->z, r->z, tempx->z, tempy->z);
336  
337      Py_DECREF((PyObject*)tempx);
338      Py_DECREF((PyObject*)tempy);
339      PyTuple_SET_ITEM(result, 0, (PyObject*)q);
340      PyTuple_SET_ITEM(result, 1, (PyObject*)r);
341      return result;
342  
343    err:
344      Py_XDECREF(result);
345      Py_XDECREF((PyObject*)tempx);
346      Py_XDECREF((PyObject*)tempy);
347      Py_XDECREF((PyObject*)q);
348      Py_XDECREF((PyObject*)r);
349      return NULL;
350  }
351  
352  PyDoc_STRVAR(doc_t_div,
353  "t_div(x, y) -> quotient\n\n"
354  "Return the quotient of x divided by y. The quotient is rounded\n"
355  "towards 0. x and y must be integers.");
356  
357  static PyObject *
358  GMPy_MPZ_t_div(PyObject *self, PyObject *args)
359  {
360      MPZ_Object *q = NULL, *tempx = NULL, *tempy = NULL;
361  
362      if (PyTuple_GET_SIZE(args) != 2) {
363          TYPE_ERROR("t_div() requires 'mpz','mpz' arguments");
364          return NULL;
365      }
366  
367  
368  
369  
370      if (!(tempx = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 0), NULL)) ||
371          !(tempy = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 1), NULL)) ||
372          !(q = GMPy_MPZ_New(NULL))) {
373  
374          goto err;
375      }
376  
377      if (mpz_sgn(tempy->z) == 0) {
378          ZERO_ERROR("t_div() division by 0");
379          goto err;
380      }
381  
382      mpz_tdiv_q(q->z, tempx->z, tempy->z);
383  
384      Py_DECREF((PyObject*)tempx);
385      Py_DECREF((PyObject*)tempy);
386      return (PyObject*)q;
387  
388    err:
389      Py_XDECREF((PyObject*)tempx);
390      Py_XDECREF((PyObject*)tempy);
391      Py_XDECREF((PyObject*)q);
392      return NULL;
393  }
394  
395  PyDoc_STRVAR(doc_t_mod,
396  "t_mod(x, y) -> remainder\n\n"
397  "Return the remainder of x divided by y. The remainder will have\n"
398  "the same sign as x. x and y must be integers.");
399  
400  static PyObject *
401  GMPy_MPZ_t_mod(PyObject *self, PyObject *args)
402  {
403      MPZ_Object *r = NULL, *tempx = NULL, *tempy = NULL;
404  
405      if (PyTuple_GET_SIZE(args) != 2) {
406          TYPE_ERROR("t_mod() requires 'mpz','mpz' arguments");
407          return NULL;
408      }
409  
410      if (!(tempx = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 0), NULL)) ||
411          !(tempy = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 1), NULL)) ||
412          !(r = GMPy_MPZ_New(NULL))) {
413  
414          goto err;
415      }
416  
417      if (mpz_sgn(tempy->z) == 0) {
418          ZERO_ERROR("t_mod() division by 0");
419          goto err;
420      }
421  
422      mpz_tdiv_r(r->z, tempx->z, tempy->z);
423  
424      Py_DECREF((PyObject*)tempx);
425      Py_DECREF((PyObject*)tempy);
426      return (PyObject*)r;
427  
428    err:
429      Py_XDECREF((PyObject*)tempx);
430      Py_XDECREF((PyObject*)tempy);
431      Py_XDECREF((PyObject*)r);
432      return NULL;
433  }