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