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