PageRenderTime 22ms CodeModel.GetById 1ms app.highlight 18ms RepoModel.GetById 1ms app.codeStats 0ms

/src/gmpy_xmpz_inplace.c

http://gmpy.googlecode.com/
C | 436 lines | 328 code | 57 blank | 51 comment | 66 complexity | 37ac1b52d55dd482403990f5d4bf8924 MD5 | raw file
  1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 * gmpy_xmpz_inplace.c                                                     *
  3 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  4 * Python interface to the GMP or MPIR, MPFR, and MPC multiple precision   *
  5 * libraries.                                                              *
  6 *                                                                         *
  7 * Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,               *
  8 *           2008, 2009 Alex Martelli                                      *
  9 *                                                                         *
 10 * Copyright 2008, 2009, 2010, 2011, 2012, 2013 Case Van Horsen            *
 11 *                                                                         *
 12 * This file is part of GMPY2.                                             *
 13 *                                                                         *
 14 * GMPY2 is free software: you can redistribute it and/or modify it under  *
 15 * the terms of the GNU Lesser General Public License as published by the  *
 16 * Free Software Foundation, either version 3 of the License, or (at your  *
 17 * option) any later version.                                              *
 18 *                                                                         *
 19 * GMPY2 is distributed in the hope that it will be useful, but WITHOUT    *
 20 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or   *
 21 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public    *
 22 * License for more details.                                               *
 23 *                                                                         *
 24 * You should have received a copy of the GNU Lesser General Public        *
 25 * License along with GMPY2; if not, see <http://www.gnu.org/licenses/>    *
 26 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 27
 28
 29/* Provides inplace mutating operations for xmpz. */
 30
 31#include <math.h>
 32
 33/* Inplace xmpz addition. */
 34
 35static PyObject *
 36Pyxmpz_inplace_add(PyObject *a, PyObject *b)
 37{
 38    mpz_t tempz;
 39    mpir_si temp_si;
 40    int overflow;
 41
 42    /* Try to make mpz + small_int faster */
 43    if (PyIntOrLong_Check(b)) {
 44        temp_si = PyLong_AsSIAndOverflow(b, &overflow);
 45        if (overflow) {
 46            mpz_inoc(tempz);
 47            mpz_set_PyIntOrLong(tempz, b);
 48            mpz_add(Pyxmpz_AS_MPZ(a), Pyxmpz_AS_MPZ(a), tempz);
 49            mpz_cloc(tempz);
 50        }
 51        else if(temp_si >= 0) {
 52            mpz_add_ui(Pyxmpz_AS_MPZ(a), Pyxmpz_AS_MPZ(a), temp_si);
 53        }
 54        else {
 55            mpz_sub_ui(Pyxmpz_AS_MPZ(a), Pyxmpz_AS_MPZ(a), -temp_si);
 56        }
 57        Py_INCREF(a);
 58        return a;
 59    }
 60
 61    if (CHECK_MPZANY(b)) {
 62        mpz_add(Pyxmpz_AS_MPZ(a), Pyxmpz_AS_MPZ(a), Pyxmpz_AS_MPZ(b));
 63        Py_INCREF(a);
 64        return a;
 65    }
 66
 67    Py_RETURN_NOTIMPLEMENTED;
 68}
 69
 70/* Inplace mpz subtraction.
 71 */
 72
 73static PyObject *
 74Pyxmpz_inplace_sub(PyObject *a, PyObject *b)
 75{
 76    mpz_t tempz;
 77    mpir_si temp_si;
 78    int overflow;
 79
 80    if (PyIntOrLong_Check(b)) {
 81        temp_si = PyLong_AsSIAndOverflow(b, &overflow);
 82        if (overflow) {
 83            mpz_inoc(tempz);
 84            mpz_set_PyIntOrLong(tempz, b);
 85            mpz_sub(Pyxmpz_AS_MPZ(a), Pyxmpz_AS_MPZ(a), tempz);
 86            mpz_cloc(tempz);
 87        }
 88        else if(temp_si >= 0) {
 89            mpz_sub_ui(Pyxmpz_AS_MPZ(a), Pyxmpz_AS_MPZ(a), temp_si);
 90        }
 91        else {
 92            mpz_add_ui(Pyxmpz_AS_MPZ(a), Pyxmpz_AS_MPZ(a), -temp_si);
 93        }
 94        Py_INCREF(a);
 95        return a;
 96    }
 97
 98    if (CHECK_MPZANY(b)) {
 99        mpz_sub(Pyxmpz_AS_MPZ(a), Pyxmpz_AS_MPZ(a), Pyxmpz_AS_MPZ(b));
100        Py_INCREF(a);
101        return a;
102    }
103
104    Py_RETURN_NOTIMPLEMENTED;
105}
106
107/* Inplace xmpz multiplication.
108 */
109
110static PyObject *
111Pyxmpz_inplace_mul(PyObject *a, PyObject *b)
112{
113    mpz_t tempz;
114    mpir_si temp_si;
115    int overflow;
116
117    if (PyIntOrLong_Check(b)) {
118        temp_si = PyLong_AsSIAndOverflow(b, &overflow);
119        if (overflow) {
120            mpz_inoc(tempz);
121            mpz_set_PyIntOrLong(tempz, b);
122            mpz_mul(Pyxmpz_AS_MPZ(a), Pyxmpz_AS_MPZ(a), tempz);
123            mpz_cloc(tempz);
124        }
125        else {
126            mpz_mul_si(Pyxmpz_AS_MPZ(a), Pyxmpz_AS_MPZ(a), temp_si);
127        }
128        Py_INCREF(a);
129        return a;
130    }
131
132    if (CHECK_MPZANY(b)) {
133        mpz_mul(Pyxmpz_AS_MPZ(a), Pyxmpz_AS_MPZ(a), Pyxmpz_AS_MPZ(b));
134        Py_INCREF(a);
135        return a;
136    }
137
138    Py_RETURN_NOTIMPLEMENTED;
139}
140
141/* Pympany_floordiv follows the // semantics from Python 3.x. The result is
142 * an mpz when the arguments are mpz or mpq, but the result is an mpf when
143 * the arguments are mpf.
144 */
145
146static PyObject *
147Pyxmpz_inplace_floordiv(PyObject *a, PyObject *b)
148{
149    mpz_t tempz;
150    mpir_si temp_si;
151    int overflow;
152
153    if (PyIntOrLong_Check(b)) {
154        temp_si = PyLong_AsSIAndOverflow(b, &overflow);
155        if (overflow) {
156            mpz_inoc(tempz);
157            mpz_set_PyIntOrLong(tempz, b);
158            mpz_fdiv_q(Pyxmpz_AS_MPZ(a), Pyxmpz_AS_MPZ(a), tempz);
159            mpz_cloc(tempz);
160        }
161        else if(temp_si == 0) {
162            ZERO_ERROR("xmpz division by zero");
163            return NULL;
164        }
165        else if(temp_si > 0) {
166            mpz_fdiv_q_ui(Pyxmpz_AS_MPZ(a), Pyxmpz_AS_MPZ(a), temp_si);
167        }
168        else {
169            mpz_cdiv_q_ui(Pyxmpz_AS_MPZ(a), Pyxmpz_AS_MPZ(a), -temp_si);
170            mpz_neg(Pyxmpz_AS_MPZ(a), Pyxmpz_AS_MPZ(a));
171        }
172        Py_INCREF(a);
173        return a;
174    }
175
176    if (CHECK_MPZANY(b)) {
177        if (mpz_sgn(Pyxmpz_AS_MPZ(b)) == 0) {
178            ZERO_ERROR("xmpz division by zero");
179            return NULL;
180        }
181        mpz_fdiv_q(Pyxmpz_AS_MPZ(a), Pyxmpz_AS_MPZ(a), Pyxmpz_AS_MPZ(b));
182        Py_INCREF(a);
183        return a;
184    }
185
186    Py_RETURN_NOTIMPLEMENTED;
187}
188
189/* Inplace xmpz remainder.
190 */
191
192static PyObject *
193Pyxmpz_inplace_rem(PyObject *a, PyObject *b)
194{
195    mpz_t tempz;
196    mpir_si temp_si;
197    int overflow;
198
199    if (PyIntOrLong_Check(b)) {
200        temp_si = PyLong_AsSIAndOverflow(b, &overflow);
201        if (overflow) {
202            mpz_inoc(tempz);
203            mpz_set_PyIntOrLong(tempz, b);
204            mpz_fdiv_r(Pyxmpz_AS_MPZ(a), Pyxmpz_AS_MPZ(a), tempz);
205            mpz_cloc(tempz);
206        }
207        else if(temp_si > 0) {
208            mpz_fdiv_r_ui(Pyxmpz_AS_MPZ(a), Pyxmpz_AS_MPZ(a), temp_si);
209        }
210        else if(temp_si == 0) {
211            ZERO_ERROR("xmpz modulo by zero");
212            return NULL;
213        }
214        else {
215            mpz_cdiv_r_ui(Pyxmpz_AS_MPZ(a), Pyxmpz_AS_MPZ(a), -temp_si);
216        }
217        Py_INCREF(a);
218        return a;
219    }
220
221    if (CHECK_MPZANY(b)) {
222        if(mpz_sgn(Pyxmpz_AS_MPZ(b)) == 0) {
223            ZERO_ERROR("xmpz modulo by zero");
224            return NULL;
225        }
226        mpz_fdiv_r(Pyxmpz_AS_MPZ(a), Pyxmpz_AS_MPZ(a), Pyxmpz_AS_MPZ(b));
227        Py_INCREF(a);
228        return a;
229    }
230
231    Py_RETURN_NOTIMPLEMENTED;
232}
233
234/* Inplace xmpz rshift.
235 */
236
237static PyObject *
238Pyxmpz_inplace_rshift(PyObject *a, PyObject *b)
239{
240    mpir_si temp_si;
241    int overflow;
242
243    if (PyIntOrLong_Check(b)) {
244        temp_si = PyLong_AsSIAndOverflow(b, &overflow);
245        if (overflow) {
246            OVERFLOW_ERROR("outrageous shift count");
247            return NULL;
248        }
249        else if(temp_si >= 0) {
250            mpz_fdiv_q_2exp(Pyxmpz_AS_MPZ(a), Pyxmpz_AS_MPZ(a), temp_si);
251            Py_INCREF(a);
252            return a;
253        }
254        else {
255            VALUE_ERROR("negative shift count");
256            return NULL;
257        }
258    }
259
260    if (CHECK_MPZANY(b)) {
261        if (mpz_sgn(Pyxmpz_AS_MPZ(b)) < 0) {
262            VALUE_ERROR("negative shift count");
263            return NULL;
264        }
265        if (!mpz_fits_si_p(Pyxmpz_AS_MPZ(b))) {
266            OVERFLOW_ERROR("outrageous shift count");
267            return NULL;
268        }
269        temp_si = mpz_get_si(Pyxmpz_AS_MPZ(b));
270        mpz_fdiv_q_2exp(Pyxmpz_AS_MPZ(a), Pyxmpz_AS_MPZ(a), temp_si);
271        Py_INCREF(a);
272        return a;
273    }
274
275    Py_RETURN_NOTIMPLEMENTED;
276}
277
278/* Inplace xmpz lshift.
279 */
280
281static PyObject *
282Pyxmpz_inplace_lshift(PyObject *a, PyObject *b)
283{
284    mpir_si temp_si;
285    int overflow;
286
287    if (PyIntOrLong_Check(b)) {
288        temp_si = PyLong_AsSIAndOverflow(b, &overflow);
289        if (overflow) {
290            OVERFLOW_ERROR("outrageous shift count");
291            return NULL;
292        }
293        else if(temp_si >= 0) {
294            mpz_mul_2exp(Pyxmpz_AS_MPZ(a), Pyxmpz_AS_MPZ(a), temp_si);
295        }
296        else {
297            VALUE_ERROR("negative shift count");
298            return NULL;
299        }
300    }
301
302    if (CHECK_MPZANY(b)) {
303        if (mpz_sgn(Pyxmpz_AS_MPZ(b)) < 0) {
304            VALUE_ERROR("negative shift count");
305            return NULL;
306        }
307        if (!mpz_fits_si_p(Pyxmpz_AS_MPZ(b))) {
308            OVERFLOW_ERROR("outrageous shift count");
309            return NULL;
310        }
311        temp_si = mpz_get_si(Pyxmpz_AS_MPZ(b));
312        mpz_mul_2exp(Pyxmpz_AS_MPZ(a), Pyxmpz_AS_MPZ(a), temp_si);
313        Py_INCREF(a);
314        return a;
315    }
316
317    Py_RETURN_NOTIMPLEMENTED;
318}
319
320/* Inplace xmpz_pow.
321 */
322
323static PyObject *
324Pyxmpz_inplace_pow(PyObject *in_b, PyObject *in_e, PyObject *in_m)
325{
326    PympzObject *e = 0;
327    mpir_ui el;
328
329    if (!Pyxmpz_Check(in_b)) {
330        PyErr_SetString(PyExc_TypeError, "base must be an Integer");
331        return NULL;
332    }
333    if (in_m != Py_None) {
334        SYSTEM_ERROR("modulo not expected");
335        return NULL;
336    }
337    e = Pympz_From_Integer(in_e);
338    if (!e) {
339        TYPE_ERROR("expected an integer exponent");
340        return NULL;
341    }
342    if (mpz_sgn(e->z) < 0) {
343        VALUE_ERROR("xmpz.pow with negative power");
344        Py_DECREF((PyObject*)e);
345        return NULL;
346    }
347    if (!mpz_fits_ui_p(e->z)) {
348        VALUE_ERROR("xmpz.pow outrageous exponent");
349        Py_DECREF((PyObject*)e);
350        return NULL;
351    }
352    el = mpz_get_ui(e->z);
353    mpz_pow_ui(Pyxmpz_AS_MPZ(in_b), Pyxmpz_AS_MPZ(in_b), el);
354    Py_DECREF((PyObject*)e);
355    Py_INCREF((PyObject*)in_b);
356    return (PyObject*)in_b;
357}
358
359/* Inplace xmpz and.
360 */
361
362static PyObject *
363Pyxmpz_inplace_and(PyObject *self, PyObject *other)
364{
365    mpz_t tempz;
366
367    if (CHECK_MPZANY(other)) {
368        mpz_and(Pyxmpz_AS_MPZ(self), Pyxmpz_AS_MPZ(self), Pyxmpz_AS_MPZ(other));
369        Py_INCREF(self);
370        return self;
371    }
372
373    if (PyIntOrLong_Check(other)) {
374        mpz_inoc(tempz);
375        mpz_set_PyIntOrLong(tempz, other);
376        mpz_and(Pyxmpz_AS_MPZ(self), Pyxmpz_AS_MPZ(self), tempz);
377        mpz_cloc(tempz);
378        Py_INCREF(self);
379        return self;
380    }
381
382    Py_RETURN_NOTIMPLEMENTED;
383}
384
385/* Inplace xmpz xor.
386 */
387
388static PyObject *
389Pyxmpz_inplace_xor(PyObject *self, PyObject *other)
390{
391    mpz_t tempz;
392
393    if(CHECK_MPZANY(other)) {
394        mpz_xor(Pyxmpz_AS_MPZ(self), Pyxmpz_AS_MPZ(self), Pyxmpz_AS_MPZ(other));
395        Py_INCREF(self);
396        return self;
397    }
398
399    if(PyIntOrLong_Check(other)) {
400        mpz_inoc(tempz);
401        mpz_set_PyIntOrLong(tempz, other);
402        mpz_xor(Pyxmpz_AS_MPZ(self), Pyxmpz_AS_MPZ(self), tempz);
403        mpz_cloc(tempz);
404        Py_INCREF(self);
405        return self;
406    }
407
408    Py_RETURN_NOTIMPLEMENTED;
409}
410
411/* Inplace xmpz or.
412 */
413
414static PyObject *
415Pyxmpz_inplace_ior(PyObject *self, PyObject *other)
416{
417    mpz_t tempz;
418
419    if(CHECK_MPZANY(other)) {
420        mpz_ior(Pyxmpz_AS_MPZ(self), Pyxmpz_AS_MPZ(self), Pyxmpz_AS_MPZ(other));
421        Py_INCREF(self);
422        return self;
423    }
424
425    if(PyIntOrLong_Check(other)) {
426        mpz_inoc(tempz);
427        mpz_set_PyIntOrLong(tempz, other);
428        mpz_ior(Pyxmpz_AS_MPZ(self), Pyxmpz_AS_MPZ(self), tempz);
429        mpz_cloc(tempz);
430        Py_INCREF(self);
431        return self;
432    }
433
434    Py_RETURN_NOTIMPLEMENTED;
435}
436