gmpy2_add.c
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 * gmpy2_add.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 the + operator, gmpy2.add(), and context.add(). 28 */ 29 30 /* Add two Integer objects (see gmpy2_convert.h). If an error occurs, NULL 31 * is returned and an exception is set. If either x or y can't be converted 32 * into an mpz, a type error is returned. 33 */ 34 35 static PyObject * 36 GMPy_Integer_AddWithType(PyObject *x, int xtype, PyObject *y, int ytype, 37 CTXT_Object *context) 38 { 39 MPZ_Object *result = NULL; 40 41 if (!(result = GMPy_MPZ_New(context))) { 42 /* LCOV_EXCL_START */ 43 return NULL; 44 /* LCOV_EXCL_STOP */ 45 } 46 47 if (IS_TYPE_MPZANY(xtype)) { 48 if (IS_TYPE_MPZANY(ytype)) { 49 mpz_add(result->z, MPZ(x), MPZ(y)); 50 return (PyObject*)result; 51 } 52 53 if (IS_TYPE_PyInteger(ytype)) { 54 int error; 55 long temp = PyLong_AsLongAndOverflow(y, &error); 56 57 if (!error) { 58 if (temp >= 0) { 59 mpz_add_ui(result->z, MPZ(x), temp); 60 } 61 else { 62 mpz_sub_ui(result->z, MPZ(x), -temp); 63 } 64 } 65 else { 66 mpz_set_PyIntOrLong(result->z, y); 67 mpz_add(result->z, MPZ(x), result->z); 68 } 69 return (PyObject*)result; 70 } 71 } 72 73 if (IS_TYPE_MPZANY(ytype)) { 74 if (IS_TYPE_PyInteger(xtype)) { 75 int error; 76 long temp = PyLong_AsLongAndOverflow(x, &error); 77 78 if (!error) { 79 if (temp >= 0) { 80 mpz_add_ui(result->z, MPZ(y), temp); 81 } 82 else { 83 mpz_sub_ui(result->z, MPZ(y), -temp); 84 } 85 } 86 else { 87 mpz_set_PyIntOrLong(result->z, x); 88 mpz_add(result->z, result->z, MPZ(y)); 89 } 90 return (PyObject*)result; 91 } 92 } 93 94 if (IS_TYPE_INTEGER(xtype) && (IS_TYPE_INTEGER(ytype))) { 95 MPZ_Object *tempx = NULL, *tempy = NULL; 96 97 if (!(tempx = GMPy_MPZ_From_IntegerWithType(x, xtype, context)) || 98 !(tempy = GMPy_MPZ_From_IntegerWithType(y, ytype, context))) { 99 /* LCOV_EXCL_START */ 100 Py_XDECREF((PyObject*)tempx); 101 Py_XDECREF((PyObject*)tempy); 102 Py_DECREF((PyObject*)result); 103 return NULL; 104 /* LCOV_EXCL_STOP */ 105 } 106 107 mpz_add(result->z, tempx->z, tempy->z); 108 Py_DECREF((PyObject*)tempx); 109 Py_DECREF((PyObject*)tempy); 110 return (PyObject*)result; 111 } 112 113 Py_DECREF((PyObject*)result); 114 TYPE_ERROR("add() argument type not supported"); 115 return NULL; 116 } 117 118 static PyObject * 119 GMPy_Rational_AddWithType(PyObject *x, int xtype, PyObject *y, int ytype, 120 CTXT_Object *context) 121 { 122 MPQ_Object *result = NULL; 123 124 if (!(result = GMPy_MPQ_New(context))) { 125 /* LCOV_EXCL_START */ 126 return NULL; 127 /* LCOV_EXCL_STOP */ 128 } 129 130 if (IS_TYPE_MPQ(xtype) && IS_TYPE_MPQ(ytype)) { 131 mpq_add(result->q, MPQ(x), MPQ(y)); 132 return (PyObject*)result; 133 } 134 135 if (IS_TYPE_RATIONAL(xtype) && IS_TYPE_RATIONAL(ytype)) { 136 MPQ_Object *tempx = NULL, *tempy = NULL; 137 138 if (!(tempx = GMPy_MPQ_From_RationalWithType(x, xtype, context)) || 139 !(tempy = GMPy_MPQ_From_RationalWithType(y, ytype, context))) { 140 /* LCOV_EXCL_START */ 141 Py_XDECREF((PyObject*)tempx); 142 Py_XDECREF((PyObject*)tempy); 143 Py_DECREF((PyObject*)result); 144 return NULL; 145 /* LCOV_EXCL_STOP */ 146 } 147 148 mpq_add(result->q, tempx->q, tempy->q); 149 Py_DECREF((PyObject*)tempx); 150 Py_DECREF((PyObject*)tempy); 151 return (PyObject*)result; 152 } 153 154 Py_DECREF((PyObject*)result); 155 TYPE_ERROR("add() argument type not supported"); 156 return NULL; 157 } 158 159 /* Addition can be performed by the equivalent of mpfr.__add__ or by 160 * gmpy2.add(). 161 * 162 * GMPy_Real_Add(x, y, context) returns x+y using the provided context. If 163 * provided context is NULL, then the current context is used. If an error 164 * occurs, NULL is returned and an exception is set. If either x or y can't 165 * be converted to an mpfr, then Py_NotImplemented is returned. 166 * GMPy_Real_Add() will not try to promote the result to a different type 167 * (i.e. mpc). 168 */ 169 170 /* Attempt to add two numbers and return an mpfr. The code path is optimized by 171 * checking for mpfr objects first. Returns Py_NotImplemented if both objects 172 * are not valid reals. */ 173 174 static PyObject * 175 GMPy_Real_AddWithType(PyObject *x, int xtype, PyObject *y, int ytype, 176 CTXT_Object *context) 177 { 178 MPFR_Object *result = NULL; 179 180 CHECK_CONTEXT(context); 181 182 if (!(result = GMPy_MPFR_New(0, context))) { 183 /* LCOV_EXCL_START */ 184 return NULL; 185 /* LCOV_EXCL_STOP */ 186 } 187 188 if (IS_TYPE_MPFR(xtype) && IS_TYPE_MPFR(ytype)) { 189 mpfr_clear_flags(); 190 result->rc = mpfr_add(result->f, MPFR(x), MPFR(y), GET_MPFR_ROUND(context)); 191 _GMPy_MPFR_Cleanup(&result, context); 192 return (PyObject*)result; 193 } 194 195 if (IS_TYPE_REAL(xtype) && IS_TYPE_REAL(ytype)) { 196 MPFR_Object *tempx = NULL, *tempy = NULL; 197 198 if (!(tempx = GMPy_MPFR_From_RealWithType(x, xtype, 1, context)) || 199 !(tempy = GMPy_MPFR_From_RealWithType(y, ytype, 1, context))) { 200 /* LCOV_EXCL_START */ 201 Py_XDECREF((PyObject*)tempx); 202 Py_XDECREF((PyObject*)tempy); 203 Py_DECREF((PyObject*)result); 204 return NULL; 205 /* LCOV_EXCL_STOP */ 206 } 207 208 mpfr_clear_flags(); 209 result->rc = mpfr_add(result->f, MPFR(tempx), MPFR(tempy), GET_MPFR_ROUND(context)); 210 Py_DECREF((PyObject*)tempx); 211 Py_DECREF((PyObject*)tempy); 212 _GMPy_MPFR_Cleanup(&result, context); 213 return (PyObject*)result; 214 } 215 216 Py_DECREF((PyObject*)result); 217 TYPE_ERROR("add() argument type not supported"); 218 return NULL; 219 } 220 221 /* GMPy_Complex_Add(x, y, context) returns x+y using the provided context. If 222 * context is NULL, then the current context is used. If an error occurs, NULL 223 * is returned and an exception is set. If either x or y can't be converted to 224 * an mpc, then Py_NotImplemented is returned. */ 225 226 227 static PyObject * 228 GMPy_Complex_AddWithType(PyObject *x, int xtype, PyObject *y, int ytype, 229 CTXT_Object *context) 230 { 231 MPC_Object *result = NULL; 232 233 CHECK_CONTEXT(context); 234 235 if (!(result = GMPy_MPC_New(0, 0, context))) { 236 /* LCOV_EXCL_START */ 237 return NULL; 238 /* LCOV_EXCL_STOP */ 239 } 240 241 if (IS_TYPE_MPC(xtype) && IS_TYPE_MPC(ytype)) { 242 result->rc = mpc_add(result->c, MPC(x), MPC(y), GET_MPC_ROUND(context)); 243 _GMPy_MPC_Cleanup(&result, context); 244 return (PyObject*)result; 245 } 246 247 if (IS_TYPE_COMPLEX(xtype) && IS_TYPE_COMPLEX(ytype)) { 248 MPC_Object *tempx = NULL, *tempy = NULL; 249 250 if (!(tempx = GMPy_MPC_From_ComplexWithType(x, xtype, 1, 1, context)) || 251 !(tempy = GMPy_MPC_From_ComplexWithType(y, ytype, 1, 1, context))) { 252 /* LCOV_EXCL_START */ 253 Py_XDECREF((PyObject*)tempx); 254 Py_XDECREF((PyObject*)tempy); 255 Py_DECREF((PyObject*)result); 256 return NULL; 257 /* LCOV_EXCL_STOP */ 258 } 259 result->rc = mpc_add(result->c, tempx->c, tempy->c, GET_MPC_ROUND(context)); 260 Py_DECREF((PyObject*)tempx); 261 Py_DECREF((PyObject*)tempy); 262 _GMPy_MPC_Cleanup(&result, context); 263 return (PyObject*)result; 264 } 265 266 Py_DECREF((PyObject*)result); 267 TYPE_ERROR("add() argument type not supported"); 268 return NULL; 269 } 270 271 /* Implement all the slot methods here. */ 272 273 static PyObject * 274 GMPy_Number_Add_Slot(PyObject *x, PyObject *y) 275 { 276 int xtype = GMPy_ObjectType(x); 277 int ytype = GMPy_ObjectType(y); 278 279 if (IS_TYPE_INTEGER(xtype) && IS_TYPE_INTEGER(ytype)) 280 return GMPy_Integer_AddWithType(x, xtype, y, ytype, NULL); 281 282 if (IS_TYPE_RATIONAL(xtype) && IS_TYPE_RATIONAL(ytype)) 283 return GMPy_Rational_AddWithType(x, xtype, y, ytype, NULL); 284 285 if (IS_TYPE_REAL(xtype) && IS_TYPE_REAL(ytype)) 286 return GMPy_Real_AddWithType(x, xtype, y, ytype, NULL); 287 288 if (IS_TYPE_COMPLEX(xtype) && IS_TYPE_COMPLEX(ytype)) 289 return GMPy_Complex_AddWithType(x, xtype, y, ytype, NULL); 290 291 Py_RETURN_NOTIMPLEMENTED; 292 } 293 294 /* Implement context.add() and gmpy2.add(). */ 295 296 PyDoc_STRVAR(GMPy_doc_function_add, 297 "add(x, y) -> number\n\n" 298 "Return x + y."); 299 300 static PyObject * 301 GMPy_Number_Add(PyObject *x, PyObject *y, CTXT_Object *context) 302 { 303 int xtype = GMPy_ObjectType(x); 304 int ytype = GMPy_ObjectType(y); 305 306 if (IS_TYPE_INTEGER(xtype) && IS_TYPE_INTEGER(ytype)) 307 return GMPy_Integer_AddWithType(x, xtype, y, ytype, context); 308 309 if (IS_TYPE_RATIONAL(xtype) && IS_TYPE_RATIONAL(ytype)) 310 return GMPy_Rational_AddWithType(x, xtype, y, ytype, context); 311 312 if (IS_TYPE_REAL(xtype) && IS_TYPE_REAL(ytype)) 313 return GMPy_Real_AddWithType(x, xtype, y, ytype, context); 314 315 if (IS_TYPE_COMPLEX(xtype) && IS_TYPE_COMPLEX(ytype)) 316 return GMPy_Complex_AddWithType(x, xtype, y, ytype, context); 317 318 TYPE_ERROR("add() argument type not supported"); 319 return NULL; 320 } 321 322 PyDoc_STRVAR(GMPy_doc_context_add, 323 "context.add(x, y) -> number\n\n" 324 "Return x + y."); 325 326 static PyObject * 327 GMPy_Context_Add(PyObject *self, PyObject *args) 328 { 329 CTXT_Object *context = NULL; 330 331 if (PyTuple_GET_SIZE(args) != 2) { 332 TYPE_ERROR("add() requires 2 arguments"); 333 return NULL; 334 } 335 336 if (self && CTXT_Check(self)) { 337 context = (CTXT_Object*)self; 338 } 339 else { 340 CHECK_CONTEXT(context); 341 } 342 343 return GMPy_Number_Add(PyTuple_GET_ITEM(args, 0), 344 PyTuple_GET_ITEM(args, 1), 345 context); 346 } 347