/ src / gmpy2_abs.c
gmpy2_abs.c
  1  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2   * gmpy2_abs.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  /* This file implements __abs__, gmpy2.abs(), and context.abs().
 28   *
 29   * Public API
 30   * ==========
 31   * The following function is available as part of GMPY2's C API. If the value
 32   * of context is NULL, then the function should use the currently active
 33   * context.
 34   *
 35   *   GMPy_Number_Abs(Number, context)
 36   *
 37   * Private API
 38   * ===========
 39   *   GMPy_MPZ_Abs_Slot
 40   *   GMPy_MPQ_Abs_Slot
 41   *   GMPy_MPFR_Abs_Slot
 42   *   GMPy_MPC_Abs_Slot
 43   *
 44   *   GMPy_Integer_AbsWithType(Integer, xtype, context|NULL)
 45   *   GMPy_Rational_AbsWithType(Rational, xtype, context|NULL)
 46   *   GMPy_Real_AbsWithType(Real, xtype, context|NULL)
 47   *   GMPy_Complex_AbsWithType(Complex, xtype, context|NULL)
 48   *
 49   *   GMPy_Context_Abs(context, obj)
 50   */
 51  
 52  static PyObject *
 53  GMPy_Integer_AbsWithType(PyObject *x, int xtype, CTXT_Object *context)
 54  {
 55      MPZ_Object *result = NULL;
 56  
 57      if (IS_TYPE_MPZ(xtype)) {
 58          if (mpz_sgn(MPZ(x)) >= 0) {
 59              Py_INCREF(x);
 60              return x;
 61          }
 62          else {
 63              if ((result = GMPy_MPZ_New(context)))
 64                  mpz_abs(result->z, MPZ(x));
 65              return (PyObject*)result;
 66          }
 67      }
 68  
 69      /* This is safe because result is not an incremented reference to an
 70       * existing value. Why?
 71       *   1) No values are interned like Python's integers.
 72       *   2) MPZ is already handled so GMPy_MPZ_From_Integer() can't return
 73       *      an incremented reference to an existing value (which it would do
 74       *      if passed an MPZ).
 75       */
 76  
 77      if ((result = GMPy_MPZ_From_IntegerWithType(x, xtype, context))) {
 78          mpz_abs(result->z, result->z);
 79      }
 80  
 81      return (PyObject*)result;
 82  }
 83  
 84  static PyObject *
 85  GMPy_MPZ_Abs_Slot(MPZ_Object *x)
 86  {
 87      return GMPy_Integer_AbsWithType((PyObject*)x, OBJ_TYPE_MPZ, NULL);
 88  }
 89  
 90  static PyObject *
 91  GMPy_Rational_AbsWithType(PyObject *x, int xtype, CTXT_Object *context)
 92  {
 93      MPQ_Object *result = NULL;
 94  
 95      if (IS_TYPE_MPQ(xtype)) {
 96          if (mpz_sgn(mpq_numref(MPQ(x))) >= 0) {
 97              Py_INCREF(x);
 98              return x;
 99          }
100          else {
101              if ((result = GMPy_MPQ_New(context))) {
102                  mpq_set(result->q, MPQ(x));
103                  mpz_abs(mpq_numref(result->q), mpq_numref(result->q));
104              }
105              return (PyObject*)result;
106          }
107      }
108  
109      /* This is safe because result is not an incremented reference to an
110       * existing value. MPQ is already handled so GMPy_MPQ_From_Rational()
111       * can't return an incremented reference to an existing value (which it
112       * would do if passed an MPQ).
113       */
114  
115      if ((result = GMPy_MPQ_From_RationalWithType(x, xtype, context))) {
116          mpz_abs(mpq_numref(result->q), mpq_numref(result->q));
117      }
118  
119      return (PyObject*)result;
120  }
121  
122  static PyObject *
123  GMPy_MPQ_Abs_Slot(MPQ_Object *x)
124  {
125      return GMPy_Rational_AbsWithType((PyObject*)x, OBJ_TYPE_MPQ, NULL);
126  }
127  
128  static PyObject *
129  GMPy_Real_AbsWithType(PyObject *x, int xtype, CTXT_Object *context)
130  {
131      MPFR_Object *result = NULL, *tempx = NULL;
132  
133      CHECK_CONTEXT(context);
134  
135      if (!(tempx = GMPy_MPFR_From_RealWithType(x, xtype, 1, context)) ||
136          !(result = GMPy_MPFR_New(0, context))) {
137          /* LCOV_EXCL_START */
138          Py_XDECREF((PyObject*)tempx);
139          Py_XDECREF((PyObject*)result);
140          return NULL;
141          /* LCOV_EXCL_STOP */
142      }
143  
144      mpfr_clear_flags();
145  
146      result->rc = mpfr_abs(result->f, tempx->f, GET_MPFR_ROUND(context));
147      Py_DECREF((PyObject*)tempx);
148  
149      _GMPy_MPFR_Cleanup(&result, context);
150      return (PyObject*)result;
151  }
152  
153  static PyObject *
154  GMPy_MPFR_Abs_Slot(MPFR_Object *x)
155  {
156      return GMPy_Real_AbsWithType((PyObject*)x, OBJ_TYPE_MPFR, NULL);
157  }
158  
159  static PyObject *
160  GMPy_Complex_AbsWithType(PyObject *x, int xtype, CTXT_Object *context)
161  {
162      MPFR_Object *result = NULL;
163      MPC_Object *tempx = NULL;
164  
165      CHECK_CONTEXT(context);
166  
167      if (!(tempx = GMPy_MPC_From_ComplexWithType(x, xtype, 1, 1, context)) ||
168          !(result = GMPy_MPFR_New(0, context))) {
169          /* LCOV_EXCL_START */
170          Py_XDECREF((PyObject*)tempx);
171          Py_XDECREF((PyObject*)result);
172          return NULL;
173          /* LCOV_EXCL_STOP */
174      }
175  
176      mpfr_clear_flags();
177  
178      result->rc = mpc_abs(result->f, tempx->c, GET_MPC_ROUND(context));
179      Py_DECREF((PyObject*)tempx);
180  
181      _GMPy_MPFR_Cleanup(&result, context);
182      return (PyObject*)result;
183  }
184  
185  static PyObject *
186  GMPy_MPC_Abs_Slot(MPC_Object *x)
187  {
188      return GMPy_Complex_AbsWithType((PyObject*)x, OBJ_TYPE_MPC, NULL);
189  }
190  
191  static PyObject *
192  GMPy_Number_Abs(PyObject *x, CTXT_Object *context)
193  {
194      int xtype = GMPy_ObjectType(x);
195      
196      if (IS_TYPE_INTEGER(xtype))
197          return GMPy_Integer_AbsWithType(x, xtype, context);
198  
199      if (IS_TYPE_RATIONAL(xtype))
200          return GMPy_Rational_AbsWithType(x, xtype, context);
201  
202      if (IS_TYPE_REAL(xtype))
203          return GMPy_Real_AbsWithType(x, xtype, context);
204  
205      if (IS_TYPE_COMPLEX(xtype))
206          return GMPy_Complex_AbsWithType(x, xtype, context);
207  
208      TYPE_ERROR("abs() argument type not supported");
209      return NULL;
210  }
211  
212  /* Implement context.abs(). The following code assumes it used a as method of
213   * a context. */
214  
215  PyDoc_STRVAR(GMPy_doc_context_abs,
216  "context.abs(x) -> number\n\n"
217  "Return abs(x), the context is applied to the result.");
218  
219  static PyObject *
220  GMPy_Context_Abs(PyObject *self, PyObject *other)
221  {
222      return GMPy_Number_Abs(other, (CTXT_Object*)self);
223  }
224