gmpy2_fused.c
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 * gmpy2_fused.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 static PyObject * 28 _GMPy_MPZ_FMA(PyObject *x, PyObject *y, PyObject *z, CTXT_Object *context) 29 { 30 MPZ_Object *result; 31 32 if (!(result = GMPy_MPZ_New(context))) { 33 /* LCOV_EXCL_START */ 34 return NULL; 35 /* LCOV_EXCL_STOP */ 36 } 37 38 mpz_mul(result->z, MPZ(x), MPZ(y)); 39 mpz_add(result->z, result->z, MPZ(z)); 40 return (PyObject*)result; 41 } 42 43 static PyObject * 44 GMPy_Integer_FMA(PyObject *x, PyObject *y, PyObject *z, CTXT_Object *context) 45 { 46 PyObject *result, *tempx = NULL, *tempy = NULL, *tempz = NULL; 47 48 if (!(tempx = (PyObject*)GMPy_MPZ_From_Integer(x, context)) || 49 !(tempy = (PyObject*)GMPy_MPZ_From_Integer(y, context)) || 50 !(tempz = (PyObject*)GMPy_MPZ_From_Integer(z, context))) { 51 /* LCOV_EXCL_START */ 52 Py_XDECREF(tempx); 53 Py_XDECREF(tempy); 54 Py_XDECREF(tempz); 55 return NULL; 56 /* LCOV_EXCL_STOP */ 57 } 58 59 result = _GMPy_MPZ_FMA(tempx, tempy, tempz, context); 60 Py_DECREF(tempx); 61 Py_DECREF(tempy); 62 Py_DECREF(tempz); 63 return result; 64 } 65 66 static PyObject * 67 _GMPy_MPQ_FMA(PyObject *x, PyObject *y, PyObject *z, CTXT_Object *context) 68 { 69 MPQ_Object *result; 70 71 if (!(result = GMPy_MPQ_New(context))) { 72 /* LCOV_EXCL_START */ 73 return NULL; 74 /* LCOV_EXCL_STOP */ 75 } 76 77 mpq_mul(result->q, MPQ(x), MPQ(y)); 78 mpq_add(result->q, result->q, MPQ(z)); 79 return (PyObject*)result; 80 } 81 82 static PyObject * 83 GMPy_Rational_FMA(PyObject *x, PyObject *y, PyObject *z, CTXT_Object *context) 84 { 85 PyObject *result, *tempx = NULL, *tempy = NULL, *tempz = NULL; 86 87 if (!(tempx = (PyObject*)GMPy_MPQ_From_Rational(x, context)) || 88 !(tempy = (PyObject*)GMPy_MPQ_From_Rational(y, context)) || 89 !(tempz = (PyObject*)GMPy_MPQ_From_Rational(z, context))) { 90 /* LCOV_EXCL_START */ 91 Py_XDECREF(tempx); 92 Py_XDECREF(tempy); 93 Py_XDECREF(tempz); 94 return NULL; 95 /* LCOV_EXCL_STOP */ 96 } 97 98 result = _GMPy_MPQ_FMA(tempx, tempy, tempz, context); 99 Py_DECREF((PyObject*)tempx); 100 Py_DECREF((PyObject*)tempy); 101 Py_DECREF((PyObject*)tempz); 102 return (result); 103 } 104 105 static PyObject * 106 _GMPy_MPFR_FMA(PyObject *x, PyObject *y, PyObject *z, CTXT_Object *context) 107 { 108 MPFR_Object *result; 109 110 CHECK_CONTEXT(context); 111 112 if (!(result = GMPy_MPFR_New(0, context))) { 113 /* LCOV_EXCL_START */ 114 return NULL; 115 /* LCOV_EXCL_STOP */ 116 } 117 118 mpfr_clear_flags(); 119 120 result->rc = mpfr_fma(result->f, MPFR(x), MPFR(y), MPFR(z), GET_MPFR_ROUND(context)); 121 _GMPy_MPFR_Cleanup(&result, context); 122 return (PyObject*)result; 123 } 124 125 static PyObject * 126 GMPy_Real_FMA(PyObject *x, PyObject *y, PyObject *z, CTXT_Object *context) 127 { 128 PyObject *result, *tempx = NULL, *tempy = NULL, *tempz = NULL; 129 130 CHECK_CONTEXT(context); 131 132 if (!(tempx = (PyObject*)GMPy_MPFR_From_Real(x, 1, context)) || 133 !(tempy = (PyObject*)GMPy_MPFR_From_Real(y, 1, context)) || 134 !(tempz = (PyObject*)GMPy_MPFR_From_Real(z, 1, context))) { 135 /* LCOV_EXCL_START */ 136 Py_XDECREF(tempx); 137 Py_XDECREF(tempy); 138 Py_XDECREF(tempz); 139 return NULL; 140 /* LCOV_EXCL_STOP */ 141 } 142 143 result = _GMPy_MPFR_FMA(tempx, tempy, tempz, context); 144 Py_DECREF(tempx); 145 Py_DECREF(tempy); 146 Py_DECREF(tempz); 147 return result; 148 } 149 150 static PyObject * 151 _GMPy_MPC_FMA(PyObject *x, PyObject *y, PyObject *z, CTXT_Object *context) 152 { 153 MPC_Object *result; 154 155 CHECK_CONTEXT(context); 156 157 if (!(result = GMPy_MPC_New(0, 0, context))) { 158 /* LCOV_EXCL_START */ 159 return NULL; 160 /* LCOV_EXCL_STOP */ 161 } 162 163 result->rc = mpc_fma(result->c, MPC(x), MPC(y), MPC(z), GET_MPC_ROUND(context)); 164 _GMPy_MPC_Cleanup(&result, context); 165 return (PyObject*)result; 166 } 167 168 static PyObject * 169 GMPy_Complex_FMA(PyObject *x, PyObject *y, PyObject *z, CTXT_Object *context) 170 { 171 PyObject *result, *tempx = NULL, *tempy = NULL, *tempz = NULL; 172 173 CHECK_CONTEXT(context); 174 175 if (!(tempx = (PyObject*)GMPy_MPC_From_Complex(x, 1, 1, context)) || 176 !(tempy = (PyObject*)GMPy_MPC_From_Complex(y, 1, 1, context)) || 177 !(tempz = (PyObject*)GMPy_MPC_From_Complex(z, 1, 1, context))) { 178 /* LCOV_EXCL_START */ 179 Py_XDECREF(tempx); 180 Py_XDECREF(tempy); 181 Py_XDECREF(tempz); 182 return NULL; 183 /* LCOV_EXCL_STOP */ 184 } 185 186 result = _GMPy_MPC_FMA(tempx, tempy, tempz, context); 187 Py_DECREF(tempx); 188 Py_DECREF(tempy); 189 Py_DECREF(tempz); 190 return result; 191 } 192 193 PyDoc_STRVAR(GMPy_doc_context_fma, 194 "context.fma(x, y, z) -> number\n\n" 195 "Return correctly rounded result of (x * y) + z."); 196 197 PyDoc_STRVAR(GMPy_doc_function_fma, 198 "fma(x, y, z) -> number\n\n" 199 "Return correctly rounded result of (x * y) + z."); 200 201 GMPY_MPFR_MPC_TRIOP_TEMPLATE(FMA, fma); 202 203 static PyObject * 204 _GMPy_MPZ_FMS(PyObject *x, PyObject *y, PyObject *z, CTXT_Object *context) 205 { 206 MPZ_Object *result; 207 208 if (!(result = GMPy_MPZ_New(context))) { 209 /* LCOV_EXCL_START */ 210 return NULL; 211 /* LCOV_EXCL_STOP */ 212 } 213 214 mpz_mul(result->z, MPZ(x), MPZ(y)); 215 mpz_sub(result->z, result->z, MPZ(z)); 216 return (PyObject*)result; 217 } 218 219 static PyObject * 220 GMPy_Integer_FMS(PyObject *x, PyObject *y, PyObject *z, CTXT_Object *context) 221 { 222 PyObject *result, *tempx = NULL, *tempy = NULL, *tempz = NULL; 223 224 if (!(tempx = (PyObject*)GMPy_MPZ_From_Integer(x, context)) || 225 !(tempy = (PyObject*)GMPy_MPZ_From_Integer(y, context)) || 226 !(tempz = (PyObject*)GMPy_MPZ_From_Integer(z, context))) { 227 /* LCOV_EXCL_START */ 228 Py_XDECREF(tempx); 229 Py_XDECREF(tempy); 230 Py_XDECREF(tempz); 231 return NULL; 232 /* LCOV_EXCL_STOP */ 233 } 234 235 result = _GMPy_MPZ_FMS(tempx, tempy, tempz, context); 236 Py_DECREF(tempx); 237 Py_DECREF(tempy); 238 Py_DECREF(tempz); 239 return result; 240 } 241 242 static PyObject * 243 _GMPy_MPQ_FMS(PyObject *x, PyObject *y, PyObject *z, CTXT_Object *context) 244 { 245 MPQ_Object *result; 246 247 if (!(result = GMPy_MPQ_New(context))) { 248 /* LCOV_EXCL_START */ 249 return NULL; 250 /* LCOV_EXCL_STOP */ 251 } 252 253 mpq_mul(result->q, MPQ(x), MPQ(y)); 254 mpq_sub(result->q, result->q, MPQ(z)); 255 return (PyObject*)result; 256 } 257 258 static PyObject * 259 GMPy_Rational_FMS(PyObject *x, PyObject *y, PyObject *z, CTXT_Object *context) 260 { 261 PyObject *result, *tempx = NULL, *tempy = NULL, *tempz = NULL; 262 263 if (!(tempx = (PyObject*)GMPy_MPQ_From_Rational(x, context)) || 264 !(tempy = (PyObject*)GMPy_MPQ_From_Rational(y, context)) || 265 !(tempz = (PyObject*)GMPy_MPQ_From_Rational(z, context))) { 266 /* LCOV_EXCL_START */ 267 Py_XDECREF(tempx); 268 Py_XDECREF(tempy); 269 Py_XDECREF(tempz); 270 return NULL; 271 /* LCOV_EXCL_STOP */ 272 } 273 274 result = _GMPy_MPQ_FMS(tempx, tempy, tempz, context); 275 Py_DECREF(tempx); 276 Py_DECREF(tempy); 277 Py_DECREF(tempz); 278 return result; 279 } 280 281 static PyObject * 282 _GMPy_MPFR_FMS(PyObject *x, PyObject *y, PyObject *z, CTXT_Object *context) 283 { 284 MPFR_Object *result; 285 286 CHECK_CONTEXT(context); 287 288 if (!(result = GMPy_MPFR_New(0, context))) { 289 /* LCOV_EXCL_START */ 290 return NULL; 291 /* LCOV_EXCL_STOP */ 292 } 293 294 mpfr_clear_flags(); 295 296 result->rc = mpfr_fms(result->f, MPFR(x), MPFR(y), MPFR(z), GET_MPFR_ROUND(context)); 297 _GMPy_MPFR_Cleanup(&result, context); 298 return (PyObject*)result; 299 } 300 301 static PyObject * 302 GMPy_Real_FMS(PyObject *x, PyObject *y, PyObject *z, CTXT_Object *context) 303 { 304 PyObject *result, *tempx = NULL, *tempy = NULL, *tempz = NULL; 305 306 CHECK_CONTEXT(context); 307 308 if (!(tempx = (PyObject*)GMPy_MPFR_From_Real(x, 1, context)) || 309 !(tempy = (PyObject*)GMPy_MPFR_From_Real(y, 1, context)) || 310 !(tempz = (PyObject*)GMPy_MPFR_From_Real(z, 1, context))) { 311 /* LCOV_EXCL_START */ 312 Py_XDECREF(tempx); 313 Py_XDECREF(tempy); 314 Py_XDECREF(tempz); 315 return NULL; 316 /* LCOV_EXCL_STOP */ 317 } 318 319 result = _GMPy_MPFR_FMS(tempx, tempy, tempz, context); 320 Py_DECREF(tempx); 321 Py_DECREF(tempy); 322 Py_DECREF(tempz); 323 return result; 324 } 325 326 static PyObject * 327 _GMPy_MPC_FMS(PyObject *x, PyObject *y, PyObject *z, CTXT_Object *context) 328 { 329 MPC_Object *result; 330 331 CHECK_CONTEXT(context); 332 333 if (!(result = GMPy_MPC_New(0, 0, context))) { 334 /* LCOV_EXCL_START */ 335 return NULL; 336 /* LCOV_EXCL_STOP */ 337 } 338 339 /* TODO: We shouldn't temporarily mutate an mpc object. */ 340 341 mpc_neg(MPC(z), MPC(z), GET_MPC_ROUND(context)); 342 result->rc = mpc_fma(result->c, MPC(x), MPC(y), MPC(z), GET_MPC_ROUND(context)); 343 mpc_neg(MPC(z), MPC(z), GET_MPC_ROUND(context)); 344 _GMPy_MPC_Cleanup(&result, context); 345 return (PyObject*)result; 346 } 347 348 static PyObject * 349 GMPy_Complex_FMS(PyObject *x, PyObject *y, PyObject *z, CTXT_Object *context) 350 { 351 PyObject *result, *tempx = NULL, *tempy = NULL, *tempz = NULL; 352 353 CHECK_CONTEXT(context); 354 355 if (!(tempx = (PyObject*)GMPy_MPC_From_Complex(x, 1, 1, context)) || 356 !(tempy = (PyObject*)GMPy_MPC_From_Complex(y, 1, 1, context)) || 357 !(tempz = (PyObject*)GMPy_MPC_From_Complex(z, 1, 1, context))) { 358 /* LCOV_EXCL_START */ 359 Py_XDECREF(tempx); 360 Py_XDECREF(tempy); 361 Py_XDECREF(tempz); 362 return NULL; 363 /* LCOV_EXCL_STOP */ 364 } 365 366 result = _GMPy_MPC_FMS(tempx, tempy, tempz, context); 367 Py_DECREF(tempx); 368 Py_DECREF(tempy); 369 Py_DECREF(tempz); 370 return result; 371 } 372 373 PyDoc_STRVAR(GMPy_doc_context_fms, 374 "context.fms(x, y, z) -> number\n\n" 375 "Return correctly rounded result of (x * y) - z."); 376 377 PyDoc_STRVAR(GMPy_doc_function_fms, 378 "fms(x, y, z) -> number\n\n" 379 "Return correctly rounded result of (x * y) - z."); 380 381 GMPY_MPFR_MPC_TRIOP_TEMPLATE(FMS, fms); 382 383 /* Add support for new fmma and fmms functions from MPFr 4. */\ 384 385 #if MPFR_VERSION_MAJOR > 3 386 387 static PyObject * 388 _GMPy_MPZ_FMMA(PyObject *x, PyObject *y, PyObject *z, PyObject *t, CTXT_Object *context) 389 { 390 MPZ_Object *result = NULL, *temp = NULL; 391 392 if (!(result = GMPy_MPZ_New(context)) || 393 !(temp = GMPy_MPZ_New(context))) { 394 /* LCOV_EXCL_START */ 395 Py_XDECREF(result); 396 Py_XDECREF(temp); 397 return NULL; 398 /* LCOV_EXCL_STOP */ 399 } 400 401 mpz_mul(result->z, MPZ(x), MPZ(y)); 402 mpz_mul(temp->z, MPZ(z), MPZ(t)); 403 mpz_add(result->z, result->z, temp->z); 404 Py_DECREF(temp); 405 return (PyObject*)result; 406 } 407 408 static PyObject * 409 GMPy_Integer_FMMA(PyObject *x, PyObject *y, PyObject *z, PyObject *t, CTXT_Object *context) 410 { 411 PyObject *result, *tempx = NULL, *tempy = NULL, *tempz = NULL, *tempt = NULL; 412 413 if (!(tempx = (PyObject*)GMPy_MPZ_From_Integer(x, context)) || 414 !(tempy = (PyObject*)GMPy_MPZ_From_Integer(y, context)) || 415 !(tempz = (PyObject*)GMPy_MPZ_From_Integer(z, context)) || 416 !(tempt = (PyObject*)GMPy_MPZ_From_Integer(t, context))) { 417 /* LCOV_EXCL_START */ 418 Py_XDECREF(tempx); 419 Py_XDECREF(tempy); 420 Py_XDECREF(tempz); 421 Py_XDECREF(tempt); 422 return NULL; 423 /* LCOV_EXCL_STOP */ 424 } 425 426 result = _GMPy_MPZ_FMMA(tempx, tempy, tempz, tempt, context); 427 Py_DECREF(tempx); 428 Py_DECREF(tempy); 429 Py_DECREF(tempz); 430 Py_DECREF(tempt); 431 return result; 432 } 433 434 static PyObject * 435 _GMPy_MPQ_FMMA(PyObject *x, PyObject *y, PyObject *z, PyObject *t, CTXT_Object *context) 436 { 437 MPQ_Object *result = NULL, *temp = NULL; 438 439 if (!(result = GMPy_MPQ_New(context)) || 440 !(temp = GMPy_MPQ_New(context))) { 441 /* LCOV_EXCL_START */ 442 Py_XDECREF(result); 443 Py_XDECREF(temp); 444 return NULL; 445 /* LCOV_EXCL_STOP */ 446 } 447 448 mpq_mul(result->q, MPQ(x), MPQ(y)); 449 mpq_mul(temp->q, MPQ(z), MPQ(t)); 450 mpq_add(result->q, result->q, temp->q); 451 Py_DECREF(temp); 452 return (PyObject*)result; 453 } 454 455 static PyObject * 456 GMPy_Rational_FMMA(PyObject *x, PyObject *y, PyObject *z, PyObject *t, CTXT_Object *context) 457 { 458 PyObject *result, *tempx = NULL, *tempy = NULL, *tempz = NULL, *tempt = NULL; 459 460 if (!(tempx = (PyObject*)GMPy_MPQ_From_Rational(x, context)) || 461 !(tempy = (PyObject*)GMPy_MPQ_From_Rational(y, context)) || 462 !(tempz = (PyObject*)GMPy_MPQ_From_Rational(z, context)) || 463 !(tempt = (PyObject*)GMPy_MPQ_From_Rational(t, context))) { 464 /* LCOV_EXCL_START */ 465 Py_XDECREF(tempx); 466 Py_XDECREF(tempy); 467 Py_XDECREF(tempz); 468 Py_XDECREF(tempt); 469 return NULL; 470 /* LCOV_EXCL_STOP */ 471 } 472 473 result = _GMPy_MPQ_FMMA(tempx, tempy, tempz, tempt, context); 474 Py_DECREF((PyObject*)tempx); 475 Py_DECREF((PyObject*)tempy); 476 Py_DECREF((PyObject*)tempz); 477 Py_DECREF((PyObject*)tempt); 478 return (result); 479 } 480 481 static PyObject * 482 _GMPy_MPFR_FMMA(PyObject *x, PyObject *y, PyObject *z, PyObject *t, CTXT_Object *context) 483 { 484 MPFR_Object *result; 485 486 CHECK_CONTEXT(context); 487 488 if (!(result = GMPy_MPFR_New(0, context))) { 489 /* LCOV_EXCL_START */ 490 return NULL; 491 /* LCOV_EXCL_STOP */ 492 } 493 494 mpfr_clear_flags(); 495 496 result->rc = mpfr_fmma(result->f, MPFR(x), MPFR(y), MPFR(z), MPFR(t), GET_MPFR_ROUND(context)); 497 _GMPy_MPFR_Cleanup(&result, context); 498 return (PyObject*)result; 499 } 500 501 static PyObject * 502 GMPy_Real_FMMA(PyObject *x, PyObject *y, PyObject *z, PyObject *t, CTXT_Object *context) 503 { 504 PyObject *result, *tempx = NULL, *tempy = NULL, *tempz = NULL, *tempt = NULL; 505 506 CHECK_CONTEXT(context); 507 508 if (!(tempx = (PyObject*)GMPy_MPFR_From_Real(x, 1, context)) || 509 !(tempy = (PyObject*)GMPy_MPFR_From_Real(y, 1, context)) || 510 !(tempz = (PyObject*)GMPy_MPFR_From_Real(z, 1, context)) || 511 !(tempt = (PyObject*)GMPy_MPFR_From_Real(t, 1, context))) { 512 /* LCOV_EXCL_START */ 513 Py_XDECREF(tempx); 514 Py_XDECREF(tempy); 515 Py_XDECREF(tempz); 516 Py_XDECREF(tempt); 517 return NULL; 518 /* LCOV_EXCL_STOP */ 519 } 520 521 result = _GMPy_MPFR_FMMA(tempx, tempy, tempz, tempt, context); 522 Py_DECREF(tempx); 523 Py_DECREF(tempy); 524 Py_DECREF(tempz); 525 Py_DECREF(tempt); 526 return result; 527 } 528 529 PyDoc_STRVAR(GMPy_doc_context_fmma, 530 "context.fmma(x, y, z, t) -> number\n\n" 531 "Return correctly rounded result of (x * y) + (z * t)."); 532 533 PyDoc_STRVAR(GMPy_doc_function_fmma, 534 "fmma(x, y, z, t) -> number\n\n" 535 "Return correctly rounded result of (x * y) + (z + t)."); 536 537 GMPY_MPFR_QUADOP_TEMPLATE(FMMA, fmma); 538 539 static PyObject * 540 _GMPy_MPZ_FMMS(PyObject *x, PyObject *y, PyObject *z, PyObject *t, CTXT_Object *context) 541 { 542 MPZ_Object *result = NULL, *temp = NULL; 543 544 if (!(result = GMPy_MPZ_New(context)) || 545 !(temp = GMPy_MPZ_New(context))) { 546 /* LCOV_EXCL_START */ 547 Py_XDECREF(result); 548 Py_XDECREF(temp); 549 return NULL; 550 /* LCOV_EXCL_STOP */ 551 } 552 553 mpz_mul(result->z, MPZ(x), MPZ(y)); 554 mpz_mul(temp->z, MPZ(z), MPZ(t)); 555 mpz_sub(result->z, result->z, temp->z); 556 Py_DECREF(temp); 557 return (PyObject*)result; 558 } 559 560 static PyObject * 561 GMPy_Integer_FMMS(PyObject *x, PyObject *y, PyObject *z, PyObject *t, CTXT_Object *context) 562 { 563 PyObject *result, *tempx = NULL, *tempy = NULL, *tempz = NULL, *tempt = NULL; 564 565 if (!(tempx = (PyObject*)GMPy_MPZ_From_Integer(x, context)) || 566 !(tempy = (PyObject*)GMPy_MPZ_From_Integer(y, context)) || 567 !(tempz = (PyObject*)GMPy_MPZ_From_Integer(z, context)) || 568 !(tempt = (PyObject*)GMPy_MPZ_From_Integer(t, context))) { 569 /* LCOV_EXCL_START */ 570 Py_XDECREF(tempx); 571 Py_XDECREF(tempy); 572 Py_XDECREF(tempz); 573 Py_XDECREF(tempt); 574 return NULL; 575 /* LCOV_EXCL_STOP */ 576 } 577 578 result = _GMPy_MPZ_FMMS(tempx, tempy, tempz, tempt, context); 579 Py_DECREF(tempx); 580 Py_DECREF(tempy); 581 Py_DECREF(tempz); 582 Py_DECREF(tempt); 583 return result; 584 } 585 586 static PyObject * 587 _GMPy_MPQ_FMMS(PyObject *x, PyObject *y, PyObject *z, PyObject *t, CTXT_Object *context) 588 { 589 MPQ_Object *result = NULL, *temp = NULL; 590 591 if (!(result = GMPy_MPQ_New(context)) || 592 !(temp = GMPy_MPQ_New(context))) { 593 /* LCOV_EXCL_START */ 594 Py_XDECREF(result); 595 Py_XDECREF(temp); 596 return NULL; 597 /* LCOV_EXCL_STOP */ 598 } 599 600 mpq_mul(result->q, MPQ(x), MPQ(y)); 601 mpq_mul(temp->q, MPQ(z), MPQ(t)); 602 mpq_sub(result->q, result->q, temp->q); 603 Py_DECREF(temp); 604 return (PyObject*)result; 605 } 606 607 static PyObject * 608 GMPy_Rational_FMMS(PyObject *x, PyObject *y, PyObject *z, PyObject *t, CTXT_Object *context) 609 { 610 PyObject *result, *tempx = NULL, *tempy = NULL, *tempz = NULL, *tempt = NULL; 611 612 if (!(tempx = (PyObject*)GMPy_MPQ_From_Rational(x, context)) || 613 !(tempy = (PyObject*)GMPy_MPQ_From_Rational(y, context)) || 614 !(tempz = (PyObject*)GMPy_MPQ_From_Rational(z, context)) || 615 !(tempt = (PyObject*)GMPy_MPQ_From_Rational(t, context))) { 616 /* LCOV_EXCL_START */ 617 Py_XDECREF(tempx); 618 Py_XDECREF(tempy); 619 Py_XDECREF(tempz); 620 Py_XDECREF(tempt); 621 return NULL; 622 /* LCOV_EXCL_STOP */ 623 } 624 625 result = _GMPy_MPQ_FMMS(tempx, tempy, tempz, tempt, context); 626 Py_DECREF((PyObject*)tempx); 627 Py_DECREF((PyObject*)tempy); 628 Py_DECREF((PyObject*)tempz); 629 Py_DECREF((PyObject*)tempt); 630 return (result); 631 } 632 633 static PyObject * 634 _GMPy_MPFR_FMMS(PyObject *x, PyObject *y, PyObject *z, PyObject *t, CTXT_Object *context) 635 { 636 MPFR_Object *result; 637 638 CHECK_CONTEXT(context); 639 640 if (!(result = GMPy_MPFR_New(0, context))) { 641 /* LCOV_EXCL_START */ 642 return NULL; 643 /* LCOV_EXCL_STOP */ 644 } 645 646 mpfr_clear_flags(); 647 648 result->rc = mpfr_fmms(result->f, MPFR(x), MPFR(y), MPFR(z), MPFR(t), GET_MPFR_ROUND(context)); 649 _GMPy_MPFR_Cleanup(&result, context); 650 return (PyObject*)result; 651 } 652 653 static PyObject * 654 GMPy_Real_FMMS(PyObject *x, PyObject *y, PyObject *z, PyObject *t, CTXT_Object *context) 655 { 656 PyObject *result, *tempx = NULL, *tempy = NULL, *tempz = NULL, *tempt = NULL; 657 658 CHECK_CONTEXT(context); 659 660 if (!(tempx = (PyObject*)GMPy_MPFR_From_Real(x, 1, context)) || 661 !(tempy = (PyObject*)GMPy_MPFR_From_Real(y, 1, context)) || 662 !(tempz = (PyObject*)GMPy_MPFR_From_Real(z, 1, context)) || 663 !(tempt = (PyObject*)GMPy_MPFR_From_Real(t, 1, context))) { 664 /* LCOV_EXCL_START */ 665 Py_XDECREF(tempx); 666 Py_XDECREF(tempy); 667 Py_XDECREF(tempz); 668 Py_XDECREF(tempt); 669 return NULL; 670 /* LCOV_EXCL_STOP */ 671 } 672 673 result = _GMPy_MPFR_FMMS(tempx, tempy, tempz, tempt, context); 674 Py_DECREF(tempx); 675 Py_DECREF(tempy); 676 Py_DECREF(tempz); 677 Py_DECREF(tempt); 678 return result; 679 } 680 681 PyDoc_STRVAR(GMPy_doc_context_fmms, 682 "context.fmms(x, y, z, t) -> number\n\n" 683 "Return correctly rounded result of (x * y) - (z * t)."); 684 685 PyDoc_STRVAR(GMPy_doc_function_fmms, 686 "fmms(x, y, z, t) -> number\n\n" 687 "Return correctly rounded result of (x * y) - (z + t)."); 688 689 GMPY_MPFR_QUADOP_TEMPLATE(FMMS, fmms); 690 691 #endif 692 693