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