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