/ src / gmpy2_cmp.c
gmpy2_cmp.c
  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  
 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  
 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 *
 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 *
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