1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  * gmpy2_cmp.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 PyDoc_STRVAR(GMPy_doc_mpany_cmp,
28 "cmp(x, y) -> integer\n\n"
29 "Return -1 if x < y; 0 if x = y; or 1 if x > y. Both x and y must be\n"
30 "integer, rational or real. Note: 0 is returned (and exception flag set)\n"
31 "if either argument is NaN.");
32 
_return_cmp(int c)33 static PyObject * _return_cmp(int c)
34 {
35     if (c < 0) return PyIntOrLong_FromLong(-1);
36     if (c > 0) return PyIntOrLong_FromLong(1);
37     return PyIntOrLong_FromLong(0);
38 }
39 
_return_negated_cmp(int c)40 static PyObject * _return_negated_cmp(int c)
41 {
42     if (c < 0) return PyIntOrLong_FromLong(1);
43     if (c > 0) return PyIntOrLong_FromLong(-1);
44     return PyIntOrLong_FromLong(0);
45 }
46 
47 static PyObject *
GMPy_MPANY_cmp(PyObject * self,PyObject * args)48 GMPy_MPANY_cmp(PyObject *self, PyObject *args)
49 {
50     PyObject *x, *y, *result = NULL;
51     int xtype, ytype;
52     CTXT_Object *context = NULL;
53 
54     CHECK_CONTEXT(context);
55 
56     if (PyTuple_GET_SIZE(args) != 2) {
57         TYPE_ERROR("cmp() requires 2 arguments");
58         return NULL;
59     }
60 
61     x = PyTuple_GET_ITEM(args, 0);
62     y = PyTuple_GET_ITEM(args, 1);
63 
64     xtype = GMPy_ObjectType(x);
65     ytype = GMPy_ObjectType(y);
66 
67     if (IS_TYPE_INTEGER(xtype) && IS_TYPE_INTEGER(ytype)) {
68         MPZ_Object *tempx = NULL, *tempy = NULL;
69 
70         if (!(tempx = GMPy_MPZ_From_IntegerWithType(x, xtype, context)) ||
71             !(tempy = GMPy_MPZ_From_IntegerWithType(y, ytype, context))) {
72             /* LCOV_EXCL_START */
73             Py_XDECREF((PyObject*)tempx);
74             Py_XDECREF((PyObject*)tempy);
75             return NULL;
76             /* LCOV_EXCL_STOP */
77         }
78 
79         result = _return_cmp(mpz_cmp(tempx->z, tempy->z));
80         Py_DECREF((PyObject*)tempx);
81         Py_DECREF((PyObject*)tempy);
82         return result;
83     }
84 
85     if (IS_TYPE_RATIONAL(xtype) && IS_TYPE_INTEGER(ytype)) {
86         MPQ_Object *tempx = NULL;
87         MPZ_Object *tempy = NULL;
88 
89         if (!(tempx = GMPy_MPQ_From_RationalWithType(x, xtype, context)) ||
90             !(tempy = GMPy_MPZ_From_IntegerWithType(y, ytype, context))) {
91             /* LCOV_EXCL_START */
92             Py_XDECREF((PyObject*)tempx);
93             Py_XDECREF((PyObject*)tempy);
94             return NULL;
95             /* LCOV_EXCL_STOP */
96         }
97 
98         result = _return_cmp(mpq_cmp_z(tempx->q, tempy->z));
99         Py_DECREF((PyObject*)tempx);
100         Py_DECREF((PyObject*)tempy);
101         return result;
102     }
103 
104     if (IS_TYPE_INTEGER(xtype) && IS_TYPE_RATIONAL(ytype)) {
105         MPZ_Object *tempx = NULL;
106         MPQ_Object *tempy = NULL;
107 
108         if (!(tempx = GMPy_MPZ_From_IntegerWithType(x, xtype, context)) ||
109             !(tempy = GMPy_MPQ_From_RationalWithType(y, ytype, context))) {
110             /* LCOV_EXCL_START */
111             Py_XDECREF((PyObject*)tempx);
112             Py_XDECREF((PyObject*)tempy);
113             return NULL;
114             /* LCOV_EXCL_STOP */
115         }
116 
117         result = _return_negated_cmp(mpq_cmp_z(tempy->q, tempx->z));
118         Py_DECREF((PyObject*)tempx);
119         Py_DECREF((PyObject*)tempy);
120         return result;
121     }
122 
123     if (IS_TYPE_RATIONAL(xtype) && IS_TYPE_RATIONAL(ytype)) {
124         MPQ_Object *tempx = NULL, *tempy = NULL;
125 
126         if (!(tempx = GMPy_MPQ_From_RationalWithType(x, xtype, context)) ||
127             !(tempy = GMPy_MPQ_From_RationalWithType(y, ytype, context))) {
128             /* LCOV_EXCL_START */
129             Py_XDECREF((PyObject*)tempx);
130             Py_XDECREF((PyObject*)tempy);
131             return NULL;
132             /* LCOV_EXCL_STOP */
133         }
134 
135         result = _return_cmp(mpq_cmp(tempx->q, tempy->q));
136         Py_DECREF((PyObject*)tempx);
137         Py_DECREF((PyObject*)tempy);
138         return result;
139     }
140 
141     /* We perform exact comparisons between the mpz, mpq, and mpfr types.
142      */
143 
144     if (IS_TYPE_REAL(xtype) && IS_TYPE_INTEGER(ytype)) {
145             MPFR_Object *tempx = NULL;
146             MPZ_Object *tempy = NULL;
147 
148         if (!(tempx = GMPy_MPFR_From_RealWithType(x, xtype, 1, context)) ||
149             !(tempy = GMPy_MPZ_From_IntegerWithType(y, ytype, context))) {
150             /* LCOV_EXCL_START */
151             Py_XDECREF((PyObject*)tempx);
152             Py_XDECREF((PyObject*)tempy);
153             return NULL;
154             /* LCOV_EXCL_STOP */
155         }
156 
157         mpfr_clear_flags();
158         result =_return_cmp(mpfr_cmp_z(tempx->f, tempy->z));
159         Py_DECREF((PyObject*)tempx);
160         Py_DECREF((PyObject*)tempy);
161         GMPY_CHECK_ERANGE(result, context, "invalid comparison with NaN");
162         return result;
163     }
164 
165     if (IS_TYPE_REAL(xtype) && IS_TYPE_RATIONAL(ytype)) {
166             MPFR_Object *tempx = NULL;
167             MPQ_Object *tempy = NULL;
168 
169         if (!(tempx = GMPy_MPFR_From_RealWithType(x, xtype, 1, context)) ||
170             !(tempy = GMPy_MPQ_From_RationalWithType(y, ytype, context))) {
171             /* LCOV_EXCL_START */
172             Py_XDECREF((PyObject*)tempx);
173             Py_XDECREF((PyObject*)tempy);
174             return NULL;
175             /* LCOV_EXCL_STOP */
176         }
177 
178         mpfr_clear_flags();
179         result =_return_cmp(mpfr_cmp_q(tempx->f, tempy->q));
180         Py_DECREF((PyObject*)tempx);
181         Py_DECREF((PyObject*)tempy);
182         GMPY_CHECK_ERANGE(result, context, "invalid comparison with NaN");
183         return result;
184     }
185 
186     if (IS_TYPE_REAL(xtype) && IS_TYPE_REAL(ytype)) {
187             MPFR_Object *tempx = NULL;
188             MPFR_Object *tempy = NULL;
189 
190         if (!(tempx = GMPy_MPFR_From_RealWithType(x, xtype, 1, context)) ||
191             !(tempy = GMPy_MPFR_From_RealWithType(y, ytype, 1, context))) {
192             /* LCOV_EXCL_START */
193             Py_XDECREF((PyObject*)tempx);
194             Py_XDECREF((PyObject*)tempy);
195             return NULL;
196             /* LCOV_EXCL_STOP */
197         }
198 
199         mpfr_clear_flags();
200         result =_return_cmp(mpfr_cmp(tempx->f, tempy->f));
201         Py_DECREF((PyObject*)tempx);
202         Py_DECREF((PyObject*)tempy);
203         GMPY_CHECK_ERANGE(result, context, "invalid comparison with NaN");
204         return result;
205     }
206 
207     if (IS_TYPE_INTEGER(xtype) && IS_TYPE_REAL(ytype)) {
208             MPZ_Object *tempx = NULL;
209             MPFR_Object *tempy = NULL;
210 
211         if (!(tempx = GMPy_MPZ_From_IntegerWithType(x, xtype, context)) ||
212             !(tempy = GMPy_MPFR_From_RealWithType(y, ytype, 1, context))) {
213             /* LCOV_EXCL_START */
214             Py_XDECREF((PyObject*)tempx);
215             Py_XDECREF((PyObject*)tempy);
216             return NULL;
217             /* LCOV_EXCL_STOP */
218         }
219 
220         mpfr_clear_flags();
221         result =_return_negated_cmp(mpfr_cmp_z(tempy->f, tempx->z));
222         Py_DECREF((PyObject*)tempx);
223         Py_DECREF((PyObject*)tempy);
224         GMPY_CHECK_ERANGE(result, context, "invalid comparison with NaN");
225         return result;
226     }
227 
228     if (IS_TYPE_RATIONAL(xtype) && IS_TYPE_REAL(ytype)) {
229             MPQ_Object *tempx = NULL;
230             MPFR_Object *tempy = NULL;
231 
232         if (!(tempx = GMPy_MPQ_From_RationalWithType(x, xtype, context)) ||
233             !(tempy = GMPy_MPFR_From_RealWithType(y, ytype, 1, context))) {
234             /* LCOV_EXCL_START */
235             Py_XDECREF((PyObject*)tempx);
236             Py_XDECREF((PyObject*)tempy);
237             return NULL;
238             /* LCOV_EXCL_STOP */
239         }
240 
241         mpfr_clear_flags();
242         result =_return_negated_cmp(mpfr_cmp_q(tempy->f, tempx->q));
243         Py_DECREF((PyObject*)tempx);
244         Py_DECREF((PyObject*)tempy);
245         GMPY_CHECK_ERANGE(result, context, "invalid comparison with NaN");
246         return result;
247     }
248 
249     TYPE_ERROR("cmp() requires integer, rational, or real arguments");
250     return NULL;
251 }
252 
253 PyDoc_STRVAR(GMPy_doc_mpany_cmp_abs,
254 "cmp_abs(x, y) -> integer\n\n"
255 "Return -1 if |x| < |y|; 0 if |x| = |y|; or 1 if |x| > |y|. Both x and y\n"
256 "can be integer, rational, real, or complex.");
257 
258 static PyObject *
GMPy_MPANY_cmp_abs(PyObject * self,PyObject * args)259 GMPy_MPANY_cmp_abs(PyObject *self, PyObject *args)
260 {
261     PyObject *x, *y, *result = NULL;
262     int xtype, ytype;
263     CTXT_Object *context = NULL;
264 
265     CHECK_CONTEXT(context);
266 
267     if (PyTuple_GET_SIZE(args) != 2) {
268         TYPE_ERROR("cmp() requires 2 arguments");
269         return NULL;
270     }
271 
272     x = PyTuple_GET_ITEM(args, 0);
273     y = PyTuple_GET_ITEM(args, 1);
274 
275     xtype = GMPy_ObjectType(x);
276     ytype = GMPy_ObjectType(y);
277 
278     if (IS_TYPE_INTEGER(xtype) && IS_TYPE_INTEGER(ytype)) {
279         MPZ_Object *tempx = NULL, *tempy = NULL;
280 
281         if (!(tempx = GMPy_MPZ_From_IntegerWithType(x, xtype, context)) ||
282             !(tempy = GMPy_MPZ_From_IntegerWithType(y, ytype, context))) {
283             /* LCOV_EXCL_START */
284             Py_XDECREF((PyObject*)tempx);
285             Py_XDECREF((PyObject*)tempy);
286             return NULL;
287             /* LCOV_EXCL_STOP */
288         }
289 
290         result = _return_cmp(mpz_cmpabs(tempx->z, tempy->z));
291         Py_DECREF((PyObject*)tempx);
292         Py_DECREF((PyObject*)tempy);
293         return result;
294     }
295 
296     if (IS_TYPE_RATIONAL(xtype) && IS_TYPE_INTEGER(ytype)) {
297         MPQ_Object *tempx = NULL;
298         MPZ_Object *tempy = NULL;
299 
300         if (!(tempx = GMPy_MPQ_From_RationalWithTypeAndCopy(x, xtype, context)) ||
301             !(tempy = GMPy_MPZ_From_IntegerWithTypeAndCopy(y, ytype, context))) {
302             /* LCOV_EXCL_START */
303             Py_XDECREF((PyObject*)tempx);
304             Py_XDECREF((PyObject*)tempy);
305             return NULL;
306             /* LCOV_EXCL_STOP */
307         }
308 
309         mpq_abs(tempx->q, tempx->q);
310         mpz_abs(tempy->z, tempy->z);
311 
312         result = _return_cmp(mpq_cmp_z(tempx->q, tempy->z));
313         Py_DECREF((PyObject*)tempx);
314         Py_DECREF((PyObject*)tempy);
315         return result;
316     }
317 
318     if (IS_TYPE_INTEGER(xtype) && IS_TYPE_RATIONAL(ytype)) {
319         MPZ_Object *tempx = NULL;
320         MPQ_Object *tempy = NULL;
321 
322         if (!(tempx = GMPy_MPZ_From_IntegerWithTypeAndCopy(x,xtype, context)) ||
323             !(tempy = GMPy_MPQ_From_RationalWithTypeAndCopy(y, ytype, context))) {
324             /* LCOV_EXCL_START */
325             Py_XDECREF((PyObject*)tempx);
326             Py_XDECREF((PyObject*)tempy);
327             return NULL;
328             /* LCOV_EXCL_STOP */
329         }
330 
331         mpz_abs(tempx->z, tempx->z);
332         mpq_abs(tempy->q, tempy->q);
333 
334         result = _return_negated_cmp(mpq_cmp_z(tempy->q, tempx->z));
335         Py_DECREF((PyObject*)tempx);
336         Py_DECREF((PyObject*)tempy);
337         return result;
338     }
339 
340     if (IS_TYPE_RATIONAL(xtype) && IS_TYPE_RATIONAL(ytype)) {
341         MPQ_Object *tempx = NULL, *tempy = NULL;
342 
343         if (!(tempx = GMPy_MPQ_From_RationalWithTypeAndCopy(x, xtype, context)) ||
344             !(tempy = GMPy_MPQ_From_RationalWithTypeAndCopy(y, ytype, context))) {
345             /* LCOV_EXCL_START */
346             Py_XDECREF((PyObject*)tempx);
347             Py_XDECREF((PyObject*)tempy);
348             return NULL;
349             /* LCOV_EXCL_STOP */
350         }
351 
352         mpq_abs(tempx->q, tempx->q);
353         mpq_abs(tempy->q, tempy->q);
354 
355         result = _return_cmp(mpq_cmp(tempx->q, tempy->q));
356         Py_DECREF((PyObject*)tempx);
357         Py_DECREF((PyObject*)tempy);
358         return result;
359     }
360 
361     /* We perform exact comparisons between the mpz, mpq, and mpfr types.
362      */
363 
364     if (IS_TYPE_REAL(xtype) && IS_TYPE_INTEGER(ytype)) {
365             MPFR_Object *tempx = NULL;
366             MPZ_Object *tempy = NULL;
367 
368         if (!(tempx = GMPy_MPFR_From_RealWithTypeAndCopy(x, xtype, 1, context)) ||
369             !(tempy = GMPy_MPZ_From_IntegerWithTypeAndCopy(y, ytype, context))) {
370             /* LCOV_EXCL_START */
371             Py_XDECREF((PyObject*)tempx);
372             Py_XDECREF((PyObject*)tempy);
373             return NULL;
374             /* LCOV_EXCL_STOP */
375         }
376 
377         mpfr_clear_flags();
378         mpfr_abs(tempx->f, tempx->f, MPFR_RNDN);
379         mpz_abs(tempy->z, tempy->z);
380 
381         result =_return_cmp(mpfr_cmp_z(tempx->f, tempy->z));
382         Py_DECREF((PyObject*)tempx);
383         Py_DECREF((PyObject*)tempy);
384         GMPY_CHECK_ERANGE(result, context, "invalid comparison with NaN");
385         return result;
386     }
387 
388     if (IS_TYPE_REAL(xtype) && IS_TYPE_RATIONAL(ytype)) {
389             MPFR_Object *tempx = NULL;
390             MPQ_Object *tempy = NULL;
391 
392         if (!(tempx = GMPy_MPFR_From_RealWithTypeAndCopy(x, xtype, 1, context)) ||
393             !(tempy = GMPy_MPQ_From_RationalWithTypeAndCopy(y, ytype, context))) {
394             /* LCOV_EXCL_START */
395             Py_XDECREF((PyObject*)tempx);
396             Py_XDECREF((PyObject*)tempy);
397             return NULL;
398             /* LCOV_EXCL_STOP */
399         }
400 
401         mpfr_clear_flags();
402         mpfr_abs(tempx->f, tempx->f, MPFR_RNDN);
403         mpq_abs(tempy->q, tempy->q);
404 
405         result =_return_cmp(mpfr_cmp_q(tempx->f, tempy->q));
406         Py_DECREF((PyObject*)tempx);
407         Py_DECREF((PyObject*)tempy);
408         GMPY_CHECK_ERANGE(result, context, "invalid comparison with NaN");
409         return result;
410     }
411 
412     if (IS_TYPE_REAL(xtype) && IS_TYPE_REAL(ytype)) {
413             MPFR_Object *tempx = NULL;
414             MPFR_Object *tempy = NULL;
415 
416         if (!(tempx = GMPy_MPFR_From_RealWithType(x, xtype, 1, context)) ||
417             !(tempy = GMPy_MPFR_From_RealWithType(y, ytype, 1, context))) {
418             /* LCOV_EXCL_START */
419             Py_XDECREF((PyObject*)tempx);
420             Py_XDECREF((PyObject*)tempy);
421             return NULL;
422             /* LCOV_EXCL_STOP */
423         }
424 
425         mpfr_clear_flags();
426         result =_return_cmp(mpfr_cmpabs(tempx->f, tempy->f));
427         Py_DECREF((PyObject*)tempx);
428         Py_DECREF((PyObject*)tempy);
429         GMPY_CHECK_ERANGE(result, context, "invalid comparison with NaN");
430         return result;
431     }
432 
433     if (IS_TYPE_INTEGER(xtype) && IS_TYPE_REAL(ytype)) {
434             MPZ_Object *tempx = NULL;
435             MPFR_Object *tempy = NULL;
436 
437         if (!(tempx = GMPy_MPZ_From_IntegerWithTypeAndCopy(x, xtype, context)) ||
438             !(tempy = GMPy_MPFR_From_RealWithTypeAndCopy(y, ytype, 1, context))) {
439             /* LCOV_EXCL_START */
440             Py_XDECREF((PyObject*)tempx);
441             Py_XDECREF((PyObject*)tempy);
442             return NULL;
443             /* LCOV_EXCL_STOP */
444         }
445 
446         mpfr_clear_flags();
447         mpz_abs(tempx->z, tempx->z);
448         mpfr_abs(tempy->f, tempy->f, MPFR_RNDN);
449 
450         result =_return_negated_cmp(mpfr_cmp_z(tempy->f, tempx->z));
451         Py_DECREF((PyObject*)tempx);
452         Py_DECREF((PyObject*)tempy);
453         GMPY_CHECK_ERANGE(result, context, "invalid comparison with NaN");
454         return result;
455     }
456 
457     if (IS_TYPE_RATIONAL(xtype) && IS_TYPE_REAL(ytype)) {
458             MPQ_Object *tempx = NULL;
459             MPFR_Object *tempy = NULL;
460 
461         if (!(tempx = GMPy_MPQ_From_RationalWithTypeAndCopy(x, xtype, context)) ||
462             !(tempy = GMPy_MPFR_From_RealWithTypeAndCopy(y, xtype, 1, context))) {
463             /* LCOV_EXCL_START */
464             Py_XDECREF((PyObject*)tempx);
465             Py_XDECREF((PyObject*)tempy);
466             return NULL;
467             /* LCOV_EXCL_STOP */
468         }
469 
470         mpfr_clear_flags();
471         mpq_abs(tempx->q, tempx->q);
472         mpfr_abs(tempy->f, tempy->f, MPFR_RNDN);
473 
474         result =_return_negated_cmp(mpfr_cmp_q(tempy->f, tempx->q));
475         Py_DECREF((PyObject*)tempx);
476         Py_DECREF((PyObject*)tempy);
477         GMPY_CHECK_ERANGE(result, context, "invalid comparison with NaN");
478         return result;
479     }
480 
481 #ifndef MPC_110
482     TYPE_ERROR("cmp_abs() requires integer, rational, or real arguments");
483     return NULL;
484 #else
485     if (IS_TYPE_COMPLEX(xtype) && IS_TYPE_COMPLEX(ytype)) {
486             MPC_Object *tempx = NULL;
487             MPC_Object *tempy = NULL;
488 
489         if (!(tempx = GMPy_MPC_From_ComplexWithType(x, xtype, 1, 1, context)) ||
490             !(tempy = GMPy_MPC_From_ComplexWithType(y, ytype, 1, 1, context))) {
491             /* LCOV_EXCL_START */
492             Py_XDECREF((PyObject*)tempx);
493             Py_XDECREF((PyObject*)tempy);
494             return NULL;
495             /* LCOV_EXCL_STOP */
496         }
497 
498         mpfr_clear_flags();
499         result =_return_cmp(mpc_cmp_abs(tempx->c, tempy->c));
500         Py_DECREF((PyObject*)tempx);
501         Py_DECREF((PyObject*)tempy);
502         GMPY_CHECK_ERANGE(result, context, "invalid comparison with NaN");
503         return result;
504     }
505 
506     TYPE_ERROR("cmp_abs() requires integer, rational, real, or complex arguments");
507     return NULL;
508 #endif
509 }
510 
511