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 *
GMPy_MPZ_c_divmod(PyObject * self,PyObject * args)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 *
GMPy_MPZ_c_div(PyObject * self,PyObject * args)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 *
GMPy_MPZ_c_mod(PyObject * self,PyObject * args)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 *
GMPy_MPZ_f_divmod(PyObject * self,PyObject * args)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 *
GMPy_MPZ_f_div(PyObject * self,PyObject * args)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 *
GMPy_MPZ_f_mod(PyObject * self,PyObject * args)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 *
GMPy_MPZ_t_divmod(PyObject * self,PyObject * args)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 *
GMPy_MPZ_t_div(PyObject * self,PyObject * args)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 *
GMPy_MPZ_t_mod(PyObject * self,PyObject * args)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 }
434