Line data Source code
1 : #line 2 "../src/kernel/gmp/mp.c"
2 : /* Copyright (C) 2002-2003 The PARI group.
3 :
4 : This file is part of the PARI/GP package.
5 :
6 : PARI/GP is free software; you can redistribute it and/or modify it under the
7 : terms of the GNU General Public License as published by the Free Software
8 : Foundation; either version 2 of the License, or (at your option) any later
9 : version. It is distributed in the hope that it will be useful, but WITHOUT
10 : ANY WARRANTY WHATSOEVER.
11 :
12 : Check the License for details. You should have received a copy of it, along
13 : with the package; see the file 'COPYING'. If not, write to the Free Software
14 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
15 :
16 : /***********************************************************************/
17 : /** **/
18 : /** GMP KERNEL **/
19 : /** BA2002Sep24 **/
20 : /***********************************************************************/
21 : /* GMP t_INT as just like normal t_INT, just the mantissa is the other way
22 : * round
23 : *
24 : * `How would you like to live in Looking-glass House, Kitty? I
25 : * wonder if they'd give you milk in there? Perhaps Looking-glass
26 : * milk isn't good to drink--But oh, Kitty! now we come to the
27 : * passage. You can just see a little PEEP of the passage in
28 : * Looking-glass House, if you leave the door of our drawing-room
29 : * wide open: and it's very like our passage as far as you can see,
30 : * only you know it may be quite different on beyond. Oh, Kitty!
31 : * how nice it would be if we could only get through into Looking-
32 : * glass House! I'm sure it's got, oh! such beautiful things in it!
33 : *
34 : * Through the Looking Glass, Lewis Carrol
35 : *
36 : * (pityful attempt to beat GN code/comments rate)
37 : * */
38 :
39 : #include <gmp.h>
40 : #include "pari.h"
41 : #include "paripriv.h"
42 : #include "../src/kernel/none/tune-gen.h"
43 :
44 : /*We need PARI invmod renamed to invmod_pari*/
45 : #define INVMOD_PARI
46 :
47 0 : static void *pari_gmp_realloc(void *ptr, size_t old_size, size_t new_size) {
48 0 : (void)old_size; return (void *) pari_realloc(ptr,new_size);
49 : }
50 :
51 1759234 : static void pari_gmp_free(void *ptr, size_t old_size){
52 1759234 : (void)old_size; pari_free(ptr);
53 1759234 : }
54 :
55 : static void *(*old_gmp_malloc)(size_t new_size);
56 : static void *(*old_gmp_realloc)(void *ptr, size_t old_size, size_t new_size);
57 : static void (*old_gmp_free)(void *ptr, size_t old_size);
58 :
59 : void
60 1112 : pari_kernel_init(void)
61 : {
62 1112 : mp_get_memory_functions (&old_gmp_malloc, &old_gmp_realloc, &old_gmp_free);
63 1112 : mp_set_memory_functions((void *(*)(size_t)) pari_malloc, pari_gmp_realloc, pari_gmp_free);
64 1112 : }
65 :
66 : const char *
67 4 : pari_kernel_version(void)
68 : {
69 : #ifdef gmp_version
70 4 : return gmp_version;
71 : #else
72 : return "";
73 : #endif
74 : }
75 :
76 : void
77 1104 : pari_kernel_close(void)
78 : {
79 : void *(*new_gmp_malloc)(size_t new_size);
80 : void *(*new_gmp_realloc)(void *ptr, size_t old_size, size_t new_size);
81 : void (*new_gmp_free)(void *ptr, size_t old_size);
82 1104 : mp_get_memory_functions (&new_gmp_malloc, &new_gmp_realloc, &new_gmp_free);
83 1104 : if (new_gmp_malloc==pari_malloc) new_gmp_malloc = old_gmp_malloc;
84 1104 : if (new_gmp_realloc==pari_gmp_realloc) new_gmp_realloc = old_gmp_realloc;
85 1104 : if (new_gmp_free==pari_gmp_free) new_gmp_free = old_gmp_free;
86 1104 : mp_set_memory_functions(new_gmp_malloc, new_gmp_realloc, new_gmp_free);
87 1104 : }
88 :
89 : #define LIMBS(x) ((mp_limb_t *)((x)+2))
90 : #define NLIMBS(x) (lgefint(x)-2)
91 : /*This one is for t_REALs to emphasize they are not t_INTs*/
92 : #define RLIMBS(x) ((mp_limb_t *)((x)+2))
93 : #define RNLIMBS(x) (lg(x)-2)
94 :
95 : INLINE void
96 6706885 : xmpn_copy(mp_limb_t *x, mp_limb_t *y, long n)
97 : {
98 55269012 : while (--n >= 0) x[n]=y[n];
99 6706885 : }
100 :
101 : INLINE void
102 584905210 : xmpn_mirror(mp_limb_t *x, long n)
103 : {
104 : long i;
105 3919888376 : for(i=0;i<(n>>1);i++)
106 : {
107 3334983166 : ulong m=x[i];
108 3334983166 : x[i]=x[n-1-i];
109 3334983166 : x[n-1-i]=m;
110 : }
111 584905210 : }
112 :
113 : INLINE void
114 716215405 : xmpn_mirrorcopy(mp_limb_t *z, mp_limb_t *x, long n)
115 : {
116 : long i;
117 9923203884 : for(i=0;i<n;i++)
118 9206988479 : z[i]=x[n-1-i];
119 716215405 : }
120 :
121 : INLINE void
122 236401478 : xmpn_zero(mp_ptr x, mp_size_t n)
123 : {
124 2069371408 : while (--n >= 0) x[n]=0;
125 236401478 : }
126 :
127 : INLINE GEN
128 41191440 : icopy_ef(GEN x, long l)
129 : {
130 41191440 : long lx = lgefint(x);
131 41191440 : const GEN y = cgeti(l);
132 :
133 293265498 : while (--lx > 0) y[lx]=x[lx];
134 41190284 : return y;
135 : }
136 :
137 : /* NOTE: arguments of "spec" routines (muliispec, addiispec, etc.) aren't
138 : * GENs but pairs (long *a, long na) representing a list of digits (in basis
139 : * BITS_IN_LONG) : a[0], ..., a[na-1]. In order to facilitate splitting: no
140 : * need to reintroduce codewords. */
141 :
142 : /***********************************************************************/
143 : /** **/
144 : /** ADDITION / SUBTRACTION **/
145 : /** **/
146 : /***********************************************************************/
147 :
148 : GEN
149 2997603 : setloop(GEN a)
150 : {
151 2997603 : pari_sp av = avma - 2 * sizeof(long);
152 2997603 : (void)cgetg(lgefint(a) + 3, t_VECSMALL);
153 2997603 : return icopy_avma(a, av); /* two cells of extra space after a */
154 : }
155 :
156 : /* we had a = setloop(?), then some incloops. Reset a to b */
157 : GEN
158 174328 : resetloop(GEN a, GEN b) {
159 174328 : a[0] = evaltyp(t_INT) | evallg(lgefint(b));
160 174328 : affii(b, a); return a;
161 : }
162 :
163 : /* assume a > 0, initialized by setloop. Do a++ */
164 : static GEN
165 103043966 : incpos(GEN a)
166 : {
167 103043966 : long i, l = lgefint(a);
168 103043971 : for (i=2; i<l; i++)
169 103046788 : if (++uel(a,i)) return a;
170 3 : a[l] = 1; l++;
171 3 : a[0]=evaltyp(t_INT) | _evallg(l);
172 3 : a[1]=evalsigne(1) | evallgefint(l);
173 3 : return a;
174 : }
175 :
176 : /* assume a < 0, initialized by setloop. Do a++ */
177 : static GEN
178 66684 : incneg(GEN a)
179 : {
180 66684 : long i, l = lgefint(a)-1;
181 66684 : if (uel(a,2)--)
182 : {
183 66680 : if (!a[l]) /* implies l = 2 */
184 : {
185 1980 : a[0] = evaltyp(t_INT) | _evallg(2);
186 1980 : a[1] = evalsigne(0) | evallgefint(2);
187 : }
188 66680 : return a;
189 : }
190 5 : for (i=3; i<=l; i++)
191 5 : if (uel(a,i)--) break;
192 4 : if (!a[l])
193 : {
194 4 : a[0] = evaltyp(t_INT) | _evallg(l);
195 4 : a[1] = evalsigne(-1) | evallgefint(l);
196 : }
197 4 : return a;
198 : }
199 :
200 : /* assume a initialized by setloop. Do a++ */
201 : GEN
202 103449670 : incloop(GEN a)
203 : {
204 103449670 : switch(signe(a))
205 : {
206 336632 : case 0:
207 336632 : a[0]=evaltyp(t_INT) | _evallg(3);
208 336632 : a[1]=evalsigne(1) | evallgefint(3);
209 336632 : a[2]=1; return a;
210 66684 : case -1: return incneg(a);
211 103046354 : default: return incpos(a);
212 : }
213 : }
214 :
215 : INLINE GEN
216 2779482985 : adduispec(ulong s, GEN x, long nx)
217 : {
218 : GEN zd;
219 : long lz;
220 :
221 2779482985 : if (nx == 1) return adduu(uel(x,0), s);
222 901153409 : lz = nx+3; zd = cgeti(lz);
223 903992392 : if (mpn_add_1(LIMBS(zd),(mp_limb_t *)x,nx,s))
224 5005487 : zd[lz-1]=1;
225 : else
226 899011498 : lz--;
227 904016985 : zd[1] = evalsigne(1) | evallgefint(lz);
228 904016985 : return zd;
229 : }
230 :
231 : GEN
232 765774087 : adduispec_offset(ulong s, GEN x, long offset, long nx)
233 : {
234 765774087 : GEN xd=x+2+offset;
235 997455483 : while (nx && *(xd+nx-1)==0) nx--;
236 765774087 : if (!nx) return utoi(s);
237 721056082 : return adduispec(s,xd,nx);
238 : }
239 :
240 : INLINE GEN
241 3319878615 : addiispec(GEN x, GEN y, long nx, long ny)
242 : {
243 : GEN zd;
244 : long lz;
245 :
246 3319878615 : if (nx < ny) swapspec(x,y, nx,ny);
247 3319878615 : if (ny == 1) return adduispec(*y,x,nx);
248 1349934146 : lz = nx+3; zd = cgeti(lz);
249 :
250 1350105375 : if (mpn_add(LIMBS(zd),(mp_limb_t *)x,nx,(mp_limb_t *)y,ny))
251 30342517 : zd[lz-1]=1;
252 : else
253 1320094595 : lz--;
254 :
255 1350437112 : zd[1] = evalsigne(1) | evallgefint(lz);
256 1350437112 : return zd;
257 : }
258 :
259 : /* assume x >= y */
260 : INLINE GEN
261 1768120392 : subiuspec(GEN x, ulong s, long nx)
262 : {
263 : GEN zd;
264 : long lz;
265 :
266 1768120392 : if (nx == 1) return utoi(x[0] - s);
267 :
268 251041389 : lz = nx + 2; zd = cgeti(lz);
269 251553164 : mpn_sub_1 (LIMBS(zd), (mp_limb_t *)x, nx, s);
270 251555225 : if (! zd[lz - 1]) { --lz; }
271 :
272 251555225 : zd[1] = evalsigne(1) | evallgefint(lz);
273 251555225 : return zd;
274 : }
275 :
276 : /* assume x > y */
277 : INLINE GEN
278 3003167652 : subiispec(GEN x, GEN y, long nx, long ny)
279 : {
280 : GEN zd;
281 : long lz;
282 3003167652 : if (ny==1) return subiuspec(x,*y,nx);
283 1265004941 : lz = nx+2; zd = cgeti(lz);
284 :
285 1262869792 : mpn_sub (LIMBS(zd), (mp_limb_t *)x, nx, (mp_limb_t *)y, ny);
286 1730680955 : while (lz >= 3 && zd[lz - 1] == 0) { lz--; }
287 :
288 1263271407 : zd[1] = evalsigne(1) | evallgefint(lz);
289 1263271407 : return zd;
290 : }
291 :
292 : static void
293 524450068 : roundr_up_ip(GEN x, long l)
294 : {
295 524450068 : long i = l;
296 : for(;;)
297 : {
298 526241387 : if (++((ulong*)x)[--i]) break;
299 2180700 : if (i == 2) { x[2] = HIGHBIT; shiftr_inplace(x, 1); break; }
300 : }
301 524498433 : }
302 :
303 : void
304 401187154 : affir(GEN x, GEN y)
305 : {
306 401187154 : const long s = signe(x), ly = lg(y);
307 : long lx, sh, i;
308 :
309 401187154 : if (!s)
310 : {
311 41784497 : y[1] = evalexpo(-bit_accuracy(ly));
312 41782256 : return;
313 : }
314 359402657 : lx = lgefint(x); sh = bfffo(*int_MSW(x));
315 359402657 : y[1] = evalsigne(s) | evalexpo(bit_accuracy(lx)-sh-1);
316 359606461 : if (sh) {
317 352088503 : if (lx <= ly)
318 : {
319 957267487 : for (i=lx; i<ly; i++) y[i]=0;
320 247665769 : mpn_lshift(LIMBS(y),LIMBS(x),lx-2,sh);
321 247791234 : xmpn_mirror(LIMBS(y),lx-2);
322 248135362 : return;
323 : }
324 104422734 : mpn_lshift(LIMBS(y),LIMBS(x)+lx-ly,ly-2,sh);
325 104424693 : uel(y,2) |= uel(x,lx-ly+1) >> (BITS_IN_LONG-sh);
326 104424693 : xmpn_mirror(LIMBS(y),ly-2);
327 : /* lx > ly: round properly */
328 104426341 : if ((uel(x,lx-ly+1)<<sh) & HIGHBIT) roundr_up_ip(y, ly);
329 : }
330 : else {
331 7517958 : GEN xd=int_MSW(x);
332 7517958 : if (lx <= ly)
333 : {
334 9515735 : for (i=2; i<lx; i++,xd=int_precW(xd)) y[i]=*xd;
335 5231213 : for ( ; i<ly; i++) y[i]=0;
336 2360496 : return;
337 : }
338 14740319 : for (i=2; i<ly; i++,xd=int_precW(xd)) y[i]=*xd;
339 : /* lx > ly: round properly */
340 5157462 : if (uel(x,lx-ly+1) & HIGHBIT) roundr_up_ip(y, ly);
341 : }
342 : }
343 :
344 : INLINE GEN
345 703541022 : shiftispec(GEN x, long nx, long n)
346 : {
347 : long ny,m;
348 : GEN yd, y;
349 :
350 703541022 : if (!n) return icopyspec(x, nx);
351 :
352 674421463 : if (n > 0)
353 : {
354 395174019 : long d = dvmdsBIL(n, &m);
355 : long i;
356 :
357 395065166 : ny = nx + d + (m!=0);
358 395065166 : y = cgeti(ny + 2); yd = y + 2;
359 548601741 : for (i=0; i<d; i++) yd[i] = 0;
360 :
361 394226566 : if (!m) xmpn_copy((mp_limb_t *) (yd + d), (mp_limb_t *) x, nx);
362 : else
363 : {
364 392695677 : ulong carryd = mpn_lshift((mp_limb_t *) (yd + d), (mp_limb_t *) x, nx, m);
365 392717781 : if (carryd) yd[ny - 1] = carryd;
366 369612298 : else ny--;
367 : }
368 : }
369 : else
370 : {
371 279247444 : long d = dvmdsBIL(-n, &m);
372 :
373 281010633 : ny = nx - d;
374 281010633 : if (ny < 1) return gen_0;
375 278167036 : y = cgeti(ny + 2); yd = y + 2;
376 :
377 277930540 : if (!m) xmpn_copy((mp_limb_t *) yd, (mp_limb_t *) (x + d), nx - d);
378 : else
379 : {
380 273439629 : mpn_rshift((mp_limb_t *) yd, (mp_limb_t *) (x + d), nx - d, m);
381 273452158 : if (yd[ny - 1] == 0)
382 : {
383 58773959 : if (ny == 1) return gc_const((pari_sp)(yd + 1), gen_0);
384 49282177 : ny--;
385 : }
386 : }
387 : }
388 660959316 : y[1] = evalsigne(1)|evallgefint(ny + 2);
389 660959316 : return y;
390 : }
391 :
392 : GEN
393 137371060 : mantissa2nr(GEN x, long n)
394 : {
395 137371060 : long ly, i, m, s = signe(x), lx = lg(x);
396 : GEN y;
397 137371060 : if (!s) return gen_0;
398 137369711 : if (!n)
399 : {
400 30204524 : y = cgeti(lx);
401 30201976 : y[1] = evalsigne(s) | evallgefint(lx);
402 30201976 : xmpn_mirrorcopy(LIMBS(y),RLIMBS(x),lx-2);
403 30201640 : return y;
404 : }
405 107165187 : if (n > 0)
406 : {
407 218263 : GEN z = (GEN)avma;
408 218263 : long d = dvmdsBIL(n, &m);
409 :
410 218263 : ly = lx+d; y = new_chunk(ly);
411 556813 : for ( ; d; d--) *--z = 0;
412 222699 : if (!m) for (i=2; i<lx; i++) y[i]=x[i];
413 : else
414 : {
415 216820 : const ulong sh = BITS_IN_LONG - m;
416 216820 : shift_left(y,x, 2,lx-1, 0,m);
417 216820 : i = uel(x,2) >> sh;
418 : /* Extend y on the left? */
419 216820 : if (i) { ly++; y = new_chunk(1); y[2] = i; }
420 : }
421 : }
422 : else
423 : {
424 106946924 : ly = lx - dvmdsBIL(-n, &m);
425 106941770 : if (ly<3) return gen_0;
426 106941770 : y = new_chunk(ly);
427 106909928 : if (m) {
428 106651654 : shift_right(y,x, 2,ly, 0,m);
429 106683959 : if (y[2] == 0)
430 : {
431 0 : if (ly==3) return gc_const((pari_sp)(y+3), gen_0);
432 0 : ly--; set_avma((pari_sp)(++y));
433 : }
434 : } else {
435 701233 : for (i=2; i<ly; i++) y[i]=x[i];
436 : }
437 : }
438 107160496 : xmpn_mirror(LIMBS(y),ly-2);
439 107202103 : y[1] = evalsigne(s)|evallgefint(ly);
440 107202103 : y[0] = evaltyp(t_INT)|evallg(ly); return y;
441 : }
442 :
443 : GEN
444 3543378 : truncr(GEN x)
445 : {
446 : long s, e, d, m, i;
447 : GEN y;
448 3543378 : if ((s=signe(x)) == 0 || (e=expo(x)) < 0) return gen_0;
449 1510661 : d = nbits2lg(e+1); m = remsBIL(e);
450 1510649 : if (d > lg(x)) pari_err_PREC( "truncr (precision loss in truncation)");
451 :
452 1510645 : y=cgeti(d); y[1] = evalsigne(s) | evallgefint(d);
453 1510585 : if (++m == BITS_IN_LONG)
454 95961 : for (i=2; i<d; i++) y[d-i+1]=x[i];
455 : else
456 : {
457 1462863 : GEN z=cgeti(d);
458 2992327 : for (i=2; i<d; i++) z[d-i+1]=x[i];
459 1462765 : mpn_rshift(LIMBS(y),LIMBS(z),d-2,BITS_IN_LONG-m);
460 1462767 : set_avma((pari_sp)y);
461 : }
462 1510476 : return y;
463 : }
464 :
465 : /* integral part */
466 : GEN
467 7001099 : floorr(GEN x)
468 : {
469 : long e, d, m, i, lx;
470 : GEN y;
471 7001099 : if (signe(x) >= 0) return truncr(x);
472 4207412 : if ((e=expo(x)) < 0) return gen_m1;
473 3520587 : d = nbits2lg(e+1); m = remsBIL(e);
474 3518649 : lx=lg(x); if (d>lx) pari_err_PREC( "floorr (precision loss in truncation)");
475 3518649 : y = cgeti(d+1);
476 3510196 : if (++m == BITS_IN_LONG)
477 : {
478 3053 : for (i=2; i<d; i++) y[d-i+1]=x[i];
479 1450 : i=d; while (i<lx && !x[i]) i++;
480 906 : if (i==lx) goto END;
481 : }
482 : else
483 : {
484 3509290 : GEN z=cgeti(d);
485 7851769 : for (i=2; i<d; i++) z[d-i+1]=x[i];
486 3497761 : mpn_rshift(LIMBS(y),LIMBS(z),d-2,BITS_IN_LONG-m);
487 3498274 : if (uel(x,d-1)<<m == 0)
488 : {
489 513773 : i=d; while (i<lx && !x[i]) i++;
490 118171 : if (i==lx) goto END;
491 : }
492 : }
493 3423211 : if (mpn_add_1(LIMBS(y),LIMBS(y),d-2,1))
494 0 : y[d++]=1;
495 3423275 : END:
496 3499244 : y[1] = evalsigne(-1) | evallgefint(d);
497 3499244 : return y;
498 : }
499 :
500 : INLINE int
501 3943191202 : cmpiispec(GEN x, GEN y, long lx, long ly)
502 : {
503 3943191202 : if (lx < ly) return -1;
504 3623988863 : if (lx > ly) return 1;
505 3474778281 : return mpn_cmp((mp_limb_t*)x,(mp_limb_t*)y, lx);
506 : }
507 :
508 : INLINE int
509 267252661 : equaliispec(GEN x, GEN y, long lx, long ly)
510 : {
511 267252661 : if (lx != ly) return 0;
512 267111649 : return !mpn_cmp((mp_limb_t*)x,(mp_limb_t*)y, lx);
513 : }
514 :
515 : /***********************************************************************/
516 : /** **/
517 : /** MULTIPLICATION **/
518 : /** **/
519 : /***********************************************************************/
520 : /* assume ny > 0 */
521 : INLINE GEN
522 5585209265 : muluispec(ulong x, GEN y, long ny)
523 : {
524 5585209265 : if (ny == 1)
525 4491774821 : return muluu(x, *y);
526 : else
527 : {
528 1093434444 : long lz = ny+3;
529 1093434444 : GEN z = cgeti(lz);
530 1102735287 : ulong hi = mpn_mul_1 (LIMBS(z), (mp_limb_t *)y, ny, x);
531 1104004796 : if (hi) { z[lz - 1] = hi; } else lz--;
532 1104004796 : z[1] = evalsigne(1) | evallgefint(lz);
533 1104004796 : return z;
534 : }
535 : }
536 :
537 : /* a + b*|y| */
538 : GEN
539 0 : addumului(ulong a, ulong b, GEN y)
540 : {
541 : GEN z;
542 : long i, lz;
543 : ulong hi;
544 0 : if (!b || !signe(y)) return utoi(a);
545 0 : lz = lgefint(y)+1;
546 0 : z = cgeti(lz);
547 0 : z[2]=a;
548 0 : for(i=3;i<lz;i++) z[i]=0;
549 0 : hi=mpn_addmul_1(LIMBS(z), LIMBS(y), NLIMBS(y), b);
550 0 : if (hi) z[lz-1]=hi; else lz--;
551 0 : z[1] = evalsigne(1) | evallgefint(lz);
552 0 : return gc_const((pari_sp)z, z);
553 : }
554 :
555 : /***********************************************************************/
556 : /** **/
557 : /** DIVISION **/
558 : /** **/
559 : /***********************************************************************/
560 :
561 : ulong
562 1303968685 : umodiu(GEN y, ulong x)
563 : {
564 1303968685 : long sy=signe(y);
565 : ulong hi;
566 1303968685 : if (!x) pari_err_INV("umodiu",gen_0);
567 1304803455 : if (!sy) return 0;
568 896417045 : hi = mpn_mod_1(LIMBS(y),NLIMBS(y),x);
569 896417045 : if (!hi) return 0;
570 880219192 : return (sy > 0)? hi: x - hi;
571 : }
572 :
573 : /* return |y| \/ x */
574 : GEN
575 109860778 : absdiviu_rem(GEN y, ulong x, ulong *rem)
576 : {
577 : long ly;
578 : GEN z;
579 :
580 109860778 : if (!x) pari_err_INV("absdiviu_rem",gen_0);
581 109865320 : if (!signe(y)) { *rem = 0; return gen_0; }
582 :
583 83124721 : ly = lgefint(y);
584 83124721 : if (ly == 3 && (ulong)x > uel(y,2)) { *rem = uel(y,2); return gen_0; }
585 :
586 68660053 : z = cgeti(ly);
587 68659681 : *rem = mpn_divrem_1(LIMBS(z), 0, LIMBS(y), NLIMBS(y), x);
588 68659602 : if (z [ly - 1] == 0) ly--;
589 68659602 : z[1] = evallgefint(ly) | evalsigne(1);
590 68659602 : return z;
591 : }
592 :
593 : GEN
594 85222431 : divis_rem(GEN y, long x, long *rem)
595 : {
596 85222431 : long sy=signe(y),ly,s;
597 : GEN z;
598 :
599 85222431 : if (!x) pari_err_INV("divis_rem",gen_0);
600 85233678 : if (!sy) { *rem = 0; return gen_0; }
601 59899244 : if (x<0) { s = -sy; x = -x; } else s = sy;
602 :
603 59899244 : ly = lgefint(y);
604 59899244 : if (ly == 3 && (ulong)x > uel(y,2)) { *rem = itos(y); return gen_0; }
605 :
606 41461762 : z = cgeti(ly);
607 41459106 : *rem = mpn_divrem_1(LIMBS(z), 0, LIMBS(y), NLIMBS(y), x);
608 41459267 : if (sy<0) *rem = - *rem;
609 41459267 : if (z[ly - 1] == 0) ly--;
610 41459267 : z[1] = evallgefint(ly) | evalsigne(s);
611 41459267 : return z;
612 : }
613 :
614 : GEN
615 966619 : divis(GEN y, long x)
616 : {
617 966619 : long sy=signe(y),ly,s;
618 : GEN z;
619 :
620 966619 : if (!x) pari_err_INV("divis",gen_0);
621 966619 : if (!sy) return gen_0;
622 966571 : if (x<0) { s = -sy; x = -x; } else s=sy;
623 :
624 966571 : ly = lgefint(y);
625 966571 : if (ly == 3 && (ulong)x > uel(y,2)) return gen_0;
626 :
627 966259 : z = cgeti(ly);
628 966257 : (void)mpn_divrem_1(LIMBS(z), 0, LIMBS(y), NLIMBS(y), x);
629 966256 : if (z[ly - 1] == 0) ly--;
630 966256 : z[1] = evallgefint(ly) | evalsigne(s);
631 966256 : return z;
632 : }
633 :
634 : /* We keep llx bits of x and lly bits of y*/
635 : static GEN
636 75794112 : divrr_with_gmp(GEN x, GEN y)
637 : {
638 75794112 : long lx=RNLIMBS(x),ly=RNLIMBS(y);
639 75794112 : long lw=minss(lx,ly);
640 75794820 : long lly=minss(lw+1,ly);
641 75795525 : GEN w = cgetg(lw+2, t_REAL);
642 75779596 : long lu=lw+lly;
643 75779596 : long llx=minss(lu,lx);
644 75776834 : mp_limb_t *u=(mp_limb_t *)new_chunk(lu);
645 75757672 : mp_limb_t *z=(mp_limb_t *)new_chunk(lly);
646 : mp_limb_t *q,*r;
647 75730779 : long e=expo(x)-expo(y);
648 75730779 : long sx=signe(x),sy=signe(y);
649 75730779 : xmpn_mirrorcopy(z,RLIMBS(y),lly);
650 75744309 : xmpn_mirrorcopy(u+lu-llx,RLIMBS(x),llx);
651 75785398 : xmpn_zero(u,lu-llx);
652 75810620 : q = (mp_limb_t *)new_chunk(lw+1);
653 75796257 : r = (mp_limb_t *)new_chunk(lly);
654 :
655 75776054 : mpn_tdiv_qr(q,r,0,u,lu,z,lly);
656 :
657 : /*Round up: This is not exactly correct we should test 2*r>z*/
658 75819339 : if (uel(r,lly-1) > (uel(z,lly-1)>>1))
659 37568909 : mpn_add_1(q,q,lw+1,1);
660 :
661 75819398 : xmpn_mirrorcopy(RLIMBS(w),q,lw);
662 :
663 75817832 : if (q[lw] == 0) e--;
664 41940058 : else if (q[lw] == 1) { shift_right(w,w, 2,lw+2, 1,1); }
665 0 : else { w[2] = HIGHBIT; e++; }
666 75816675 : if (sy < 0) sx = -sx;
667 75816675 : w[1] = evalsigne(sx) | evalexpo(e);
668 75811729 : return gc_const((pari_sp)w, w);
669 : }
670 :
671 : /* We keep llx bits of x and lly bits of y*/
672 : static GEN
673 35235553 : divri_with_gmp(GEN x, GEN y)
674 : {
675 35235553 : long llx=RNLIMBS(x),ly=NLIMBS(y);
676 35235553 : long lly=minss(llx+1,ly);
677 35235727 : GEN w = cgetg(llx+2, t_REAL);
678 35232071 : long lu=llx+lly, ld=ly-lly;
679 35232071 : mp_limb_t *u=(mp_limb_t *)new_chunk(lu);
680 35229067 : mp_limb_t *z=(mp_limb_t *)new_chunk(lly);
681 : mp_limb_t *q,*r;
682 35224385 : long sh=bfffo(y[ly+1]);
683 35224385 : long e=expo(x)-expi(y);
684 35225086 : long sx=signe(x),sy=signe(y);
685 35225086 : if (sh) mpn_lshift(z,LIMBS(y)+ld,lly,sh);
686 685100 : else xmpn_copy(z,LIMBS(y)+ld,lly);
687 35226662 : xmpn_mirrorcopy(u+lu-llx,RLIMBS(x),llx);
688 35233026 : xmpn_zero(u,lu-llx);
689 35237803 : q = (mp_limb_t *)new_chunk(llx+1);
690 35236164 : r = (mp_limb_t *)new_chunk(lly);
691 :
692 35232205 : mpn_tdiv_qr(q,r,0,u,lu,z,lly);
693 :
694 : /*Round up: This is not exactly correct we should test 2*r>z*/
695 35240524 : if (uel(r,lly-1) > (uel(z,lly-1)>>1))
696 16037692 : mpn_add_1(q,q,llx+1,1);
697 :
698 35240531 : xmpn_mirrorcopy(RLIMBS(w),q,llx);
699 :
700 35240267 : if (q[llx] == 0) e--;
701 10619843 : else if (q[llx] == 1) { shift_right(w,w, 2,llx+2, 1,1); }
702 0 : else { w[2] = HIGHBIT; e++; }
703 35240157 : if (sy < 0) sx = -sx;
704 35240157 : w[1] = evalsigne(sx) | evalexpo(e);
705 35239271 : return gc_const((pari_sp)w, w);
706 : }
707 :
708 : GEN
709 151126210 : divri(GEN x, GEN y)
710 : {
711 151126210 : long s = signe(y);
712 :
713 151126210 : if (!s) pari_err_INV("divri",gen_0);
714 151126356 : if (!signe(x)) return real_0_bit(expo(x) - expi(y));
715 150894778 : if (!is_bigint(y)) {
716 115664086 : GEN z = divru(x, y[2]);
717 115663094 : if (s < 0) togglesign(z);
718 115663112 : return z;
719 : }
720 35230007 : return divri_with_gmp(x,y);
721 : }
722 :
723 : GEN
724 141823454 : divrr(GEN x, GEN y)
725 : {
726 141823454 : long sx=signe(x), sy=signe(y), lx,ly,lr,e,i,j;
727 : ulong y0,y1;
728 : GEN r, r1;
729 :
730 141823454 : if (!sy) pari_err_INV("divrr",y);
731 141831579 : e = expo(x) - expo(y);
732 141831579 : if (!sx) return real_0_bit(e);
733 141327008 : if (sy<0) sx = -sx;
734 :
735 141327008 : lx=lg(x); ly=lg(y);
736 141327008 : if (ly==3)
737 : {
738 26289310 : ulong k = x[2], l = (lx>3)? x[3]: 0;
739 : LOCAL_HIREMAINDER;
740 26289310 : if (k < uel(y,2)) e--;
741 : else
742 : {
743 8278215 : l >>= 1; if (k&1) l |= HIGHBIT;
744 8278215 : k >>= 1;
745 : }
746 26289310 : hiremainder = k; k = divll(l,y[2]);
747 26289310 : if (hiremainder > (uel(y,2) >> 1) && !++k) { k = HIGHBIT; e++; }
748 26289310 : r = cgetg(3, t_REAL);
749 26291304 : r[1] = evalsigne(sx) | evalexpo(e);
750 26289270 : r[2] = k; return r;
751 : }
752 :
753 115037698 : if (ly >= prec2lg(DIVRR_GMP_LIMIT))
754 75793731 : return divrr_with_gmp(x,y);
755 :
756 39290876 : lr = minss(lx,ly); r = new_chunk(lr);
757 39298179 : r1 = r-1;
758 133469256 : r1[1] = 0; for (i=2; i<lr; i++) r1[i]=x[i];
759 39298179 : r1[lr] = (lx>ly)? x[lr]: 0;
760 39298179 : y0 = y[2]; y1 = y[3];
761 172726434 : for (i=0; i<lr-1; i++)
762 : { /* r1 = r + (i-1), OK up to r1[2] (accesses at most r[lr]) */
763 : ulong k, qp;
764 : LOCAL_HIREMAINDER;
765 : LOCAL_OVERFLOW;
766 :
767 133428255 : if (uel(r1,1) == y0) { qp = ULONG_MAX; k = addll(y0,r1[2]); }
768 : else
769 : {
770 133181842 : if (uel(r1,1) > y0) /* can't happen if i=0 */
771 : {
772 0 : GEN y1 = y+1;
773 0 : j = lr-i; r1[j] = subll(r1[j],y1[j]);
774 0 : for (j--; j>0; j--) r1[j] = subllx(r1[j],y1[j]);
775 0 : j=i; do uel(r,--j)++; while (j && !r[j]);
776 : }
777 133181842 : hiremainder = r1[1]; overflow = 0;
778 133181842 : qp = divll(r1[2],y0); k = hiremainder;
779 : }
780 133428255 : j = lr-i+1;
781 133428255 : if (!overflow)
782 : {
783 : long k3, k4;
784 133283597 : k3 = mulll(qp,y1);
785 133283597 : if (j == 3) /* i = lr - 2 maximal, r1[3] undefined -> 0 */
786 39351229 : k4 = subll(hiremainder,k);
787 : else
788 : {
789 93932368 : k3 = subll(k3, r1[3]);
790 93932368 : k4 = subllx(hiremainder,k);
791 : }
792 170982309 : while (!overflow && k4) { qp--; k3=subll(k3,y1); k4=subllx(k4,y0); }
793 : }
794 133428255 : if (j<ly) (void)mulll(qp,y[j]); else { hiremainder = 0 ; j = ly; }
795 395868482 : for (j--; j>1; j--)
796 : {
797 262440227 : r1[j] = subll(r1[j], addmul(qp,y[j]));
798 262440227 : hiremainder += overflow;
799 : }
800 133428255 : if (uel(r1,1) != hiremainder)
801 : {
802 182863 : if (uel(r1,1) < hiremainder)
803 : {
804 182863 : qp--;
805 182863 : j = lr-i-(lr-i>=ly); r1[j] = addll(r1[j], y[j]);
806 521125 : for (j--; j>1; j--) r1[j] = addllx(r1[j], y[j]);
807 : }
808 : else
809 : {
810 0 : uel(r1,1) -= hiremainder;
811 0 : while (r1[1])
812 : {
813 0 : qp++; if (!qp) { j=i; do uel(r,--j)++; while (j && !r[j]); }
814 0 : j = lr-i-(lr-i>=ly); r1[j] = subll(r1[j],y[j]);
815 0 : for (j--; j>1; j--) r1[j] = subllx(r1[j],y[j]);
816 0 : uel(r1,1) -= overflow;
817 : }
818 : }
819 : }
820 133428255 : *++r1 = qp;
821 : }
822 : /* i = lr-1 */
823 : /* round correctly */
824 39298179 : if (uel(r1,1) > (y0>>1))
825 : {
826 19809437 : j=i; do uel(r,--j)++; while (j && !r[j]);
827 : }
828 133645747 : r1 = r-1; for (j=i; j>=2; j--) r[j]=r1[j];
829 39298179 : if (r[0] == 0) e--;
830 14181202 : else if (r[0] == 1) { shift_right(r,r, 2,lr, 1,1); }
831 : else { /* possible only when rounding up to 0x2 0x0 ... */
832 18 : r[2] = (long)HIGHBIT; e++;
833 : }
834 39297124 : r[0] = evaltyp(t_REAL)|evallg(lr);
835 39352953 : r[1] = evalsigne(sx) | evalexpo(e);
836 39345934 : return r;
837 : }
838 :
839 : /* Integer division x / y: such that sign(r) = sign(x)
840 : * if z = ONLY_REM return remainder, otherwise return quotient
841 : * if z != NULL set *z to remainder
842 : * *z is the last object on stack and can be disposed of with cgiv
843 : * If *z is zero, we put gen_0 here and no copy.
844 : * space needed: lx + ly
845 : */
846 : GEN
847 2178597692 : dvmdii(GEN x, GEN y, GEN *z)
848 : {
849 2178597692 : long sx=signe(x),sy=signe(y);
850 : long lx, ly, lq;
851 : pari_sp av;
852 : GEN r,q;
853 :
854 2178597692 : if (!sy) pari_err_INV("dvmdii",y);
855 2179652328 : if (!sx)
856 : {
857 68106691 : if (!z || z == ONLY_REM) return gen_0;
858 40576752 : *z=gen_0; return gen_0;
859 : }
860 2111545637 : lx=lgefint(x);
861 2111545637 : ly=lgefint(y); lq=lx-ly;
862 2111545637 : if (lq <= 0)
863 : {
864 1250505337 : if (lq == 0)
865 : {
866 1062565335 : long s=mpn_cmp(LIMBS(x),LIMBS(y),NLIMBS(x));
867 1062565335 : if (s>0) goto DIVIDE;
868 363908128 : if (s==0)
869 : {
870 32674473 : if (z == ONLY_REM) return gen_0;
871 22135372 : if (z) *z = gen_0;
872 22135372 : if (sx < 0) sy = -sy;
873 22135372 : return stoi(sy);
874 : }
875 : }
876 519173657 : if (z == ONLY_REM) return icopy(x);
877 14028855 : if (z) *z = icopy(x);
878 14028855 : return gen_0;
879 : }
880 861040300 : DIVIDE: /* quotient is nonzero */
881 1559697507 : av=avma; if (sx<0) sy = -sy;
882 1559697507 : if (ly==3)
883 : {
884 570972639 : ulong lq = lx;
885 : ulong si;
886 570972639 : q = cgeti(lq);
887 570628358 : si = mpn_divrem_1(LIMBS(q), 0, LIMBS(x), NLIMBS(x), y[2]);
888 571140246 : if (q[lq - 1] == 0) lq--;
889 571140246 : if (z == ONLY_REM)
890 : {
891 331935811 : if (!si) return gc_const(av, gen_0);
892 286439084 : set_avma(av); r = cgeti(3);
893 285950157 : r[1] = evalsigne(sx) | evallgefint(3);
894 285950157 : r[2] = si; return r;
895 : }
896 239204435 : q[1] = evalsigne(sy) | evallgefint(lq);
897 239204435 : if (!z) return q;
898 235101052 : if (!si) { *z=gen_0; return q; }
899 63691597 : r=cgeti(3);
900 63713794 : r[1] = evalsigne(sx) | evallgefint(3);
901 63713794 : r[2] = si; *z=r; return q;
902 : }
903 988724868 : if (z == ONLY_REM)
904 : {
905 965189021 : ulong lr = lgefint(y);
906 965189021 : ulong lq = lgefint(x)-lgefint(y)+3;
907 965189021 : GEN r = cgeti(lr);
908 959389458 : GEN q = cgeti(lq);
909 952725378 : mpn_tdiv_qr(LIMBS(q), LIMBS(r),0, LIMBS(x), NLIMBS(x), LIMBS(y), NLIMBS(y));
910 966822425 : if (!r[lr - 1])
911 : {
912 1180526437 : while(lr>2 && !r[lr - 1]) lr--;
913 544883354 : if (lr == 2) return gc_const(av, gen_0); /* exact division */
914 : }
915 951931811 : r[1] = evalsigne(sx) | evallgefint(lr);
916 951931811 : return gc_const((pari_sp)r, r);
917 : }
918 : else
919 : {
920 23535847 : ulong lq = lgefint(x)-lgefint(y)+3;
921 23535847 : ulong lr = lgefint(y);
922 23535847 : GEN q = cgeti(lq);
923 28469934 : GEN r = cgeti(lr);
924 28459149 : mpn_tdiv_qr(LIMBS(q), LIMBS(r),0, LIMBS(x), NLIMBS(x), LIMBS(y), NLIMBS(y));
925 28481437 : if (q[lq - 1] == 0) lq--;
926 28481437 : q[1] = evalsigne(sy) | evallgefint(lq);
927 28481437 : if (!z) return gc_const((pari_sp)q, q);
928 24788851 : if (!r[lr - 1])
929 : {
930 38518133 : while(lr>2 && !r[lr - 1]) lr--;
931 6343707 : if (lr == 2) { *z = gen_0; return gc_const((pari_sp)q, q); } /* exact */
932 : }
933 19999818 : r[1] = evalsigne(sx) | evallgefint(lr);
934 19999818 : *z = gc_const((pari_sp)r, r); return q;
935 : }
936 : }
937 :
938 : /* Montgomery reduction.
939 : * N has k words, assume T >= 0 has less than 2k.
940 : * Return res := T / B^k mod N, where B = 2^BIL
941 : * such that 0 <= res < T/B^k + N and res has less than k words */
942 : GEN
943 33641261 : red_montgomery(GEN T, GEN N, ulong inv)
944 : {
945 : pari_sp av;
946 : GEN Te, Td, Ne, Nd, scratch;
947 33641261 : ulong i, j, m, t, d, k = NLIMBS(N);
948 : int carry;
949 : LOCAL_HIREMAINDER;
950 : LOCAL_OVERFLOW;
951 :
952 33641261 : if (k == 0) return gen_0;
953 33641261 : d = NLIMBS(T); /* <= 2*k */
954 33641261 : if (d == 0) return gen_0;
955 : #ifdef DEBUG
956 : if (d > 2*k) pari_err_BUG("red_montgomery");
957 : #endif
958 33641252 : if (k == 1)
959 : { /* as below, special cased for efficiency */
960 163341 : ulong n = uel(N,2);
961 163341 : if (d == 1) {
962 163194 : hiremainder = uel(T,2);
963 163194 : m = hiremainder * inv;
964 163194 : (void)addmul(m, n); /* t + m*n = 0 */
965 163194 : return utoi(hiremainder);
966 : } else { /* d = 2 */
967 147 : hiremainder = uel(T,2);
968 147 : m = hiremainder * inv;
969 147 : (void)addmul(m, n); /* t + m*n = 0 */
970 147 : t = addll(hiremainder, uel(T,3));
971 147 : if (overflow) t -= n; /* t > n doesn't fit in 1 word */
972 147 : return utoi(t);
973 : }
974 : }
975 : /* assume k >= 2 */
976 33477911 : av = avma; scratch = new_chunk(k<<1); /* >= k + 2: result fits */
977 :
978 : /* copy T to scratch space (pad with zeroes to 2k words) */
979 33112578 : Td = scratch;
980 33112578 : Te = T + 2;
981 454002674 : for (i=0; i < d ; i++) *Td++ = *Te++;
982 59868705 : for ( ; i < (k<<1); i++) *Td++ = 0;
983 :
984 33112578 : Te = scratch - 1; /* 1 beyond end of current T mantissa (in scratch) */
985 33112578 : Ne = N + 1; /* 1 beyond end of N mantissa */
986 :
987 33112578 : carry = 0;
988 244202392 : for (i=0; i<k; i++) /* set T := T/B nod N, k times */
989 : {
990 211089814 : Td = Te; /* one beyond end of (new) T mantissa */
991 211089814 : Nd = Ne;
992 211089814 : hiremainder = *++Td;
993 211089814 : m = hiremainder * inv; /* solve T + m N = O(B) */
994 :
995 : /* set T := (T + mN) / B */
996 211089814 : Te = Td;
997 211089814 : (void)addmul(m, *++Nd); /* = 0 */
998 1803745429 : for (j=1; j<k; j++)
999 : {
1000 1592655615 : t = addll(addmul(m, *++Nd), *++Td);
1001 1592655615 : *Td = t;
1002 1592655615 : hiremainder += overflow;
1003 : }
1004 211089814 : t = addll(hiremainder, *++Td); *Td = t + carry;
1005 211089814 : carry = (overflow || (carry && *Td == 0));
1006 : }
1007 33112578 : if (carry)
1008 : { /* Td > N overflows (k+1 words), set Td := Td - N */
1009 62408 : GEN NE = N + k+1;
1010 62408 : Td = Te;
1011 62408 : Nd = Ne;
1012 62408 : t = subll(*++Td, *++Nd); *Td = t;
1013 607099 : while (Nd < NE) { t = subllx(*++Td, *++Nd); *Td = t; }
1014 : }
1015 :
1016 : /* copy result */
1017 33112578 : Td = (GEN)av - 1; /* *Td = high word of final result */
1018 36582040 : while (*Td == 0 && Te < Td) Td--; /* strip leading 0s */
1019 33112578 : k = Td - Te; if (!k) return gc_const(av, gen_0);
1020 33112578 : Td = (GEN)av - k; /* will write mantissa there */
1021 33112578 : (void)memmove(Td, Te+1, k*sizeof(long));
1022 33112578 : Td -= 2;
1023 33112578 : Td[0] = evaltyp(t_INT) | evallg(k+2);
1024 33455850 : Td[1] = evalsigne(1) | evallgefint(k+2);
1025 : #ifdef DEBUG
1026 : {
1027 : long l = NLIMBS(N), s = BITS_IN_LONG*l;
1028 : GEN R = int2n(s);
1029 : GEN res = remii(mulii(T, Fp_inv(R, N)), N);
1030 : if (k > lgefint(N)
1031 : || !equalii(remii(Td,N),res)
1032 : || cmpii(Td, addii(shifti(T, -s), N)) >= 0) pari_err_BUG("red_montgomery");
1033 : }
1034 : #endif
1035 33455850 : return gc_const((pari_sp)Td, Td);
1036 : }
1037 :
1038 : /* EXACT INTEGER DIVISION */
1039 :
1040 : /* use undocumented GMP interface */
1041 : static void
1042 115122768 : GEN2mpz(mpz_t X, GEN x)
1043 : {
1044 115122768 : long l = lgefint(x)-2;
1045 115122768 : X->_mp_alloc = l;
1046 115122768 : X->_mp_size = signe(x) > 0? l: -l;
1047 115122768 : X->_mp_d = LIMBS(x);
1048 115122768 : }
1049 : static void
1050 57562364 : mpz2GEN(GEN z, mpz_t Z)
1051 : {
1052 57562364 : long l = Z->_mp_size;
1053 57562364 : z[1] = evalsigne(l > 0? 1: -1) | evallgefint(labs(l)+2);
1054 57562364 : }
1055 :
1056 : #ifdef mpn_divexact_1
1057 : static GEN
1058 413739934 : diviuexact_i(GEN x, ulong y)
1059 : {
1060 413739934 : long l = lgefint(x);
1061 413739934 : GEN z = cgeti(l);
1062 413308635 : mpn_divexact_1(LIMBS(z), LIMBS(x), NLIMBS(x), y);
1063 413365133 : if (z[l-1] == 0) l--;
1064 413365133 : z[1] = evallgefint(l) | evalsigne(signe(x));
1065 413365133 : return z;
1066 : }
1067 : #elif 1 && !defined(_WIN64) /* mpz_divexact_ui is not LLP64 friendly */
1068 : /* assume y != 0 and the division is exact */
1069 : static GEN
1070 : diviuexact_i(GEN x, ulong y)
1071 : {
1072 : long l = lgefint(x);
1073 : GEN z = cgeti(l);
1074 : mpz_t X, Z;
1075 : GEN2mpz(X, x);
1076 : Z->_mp_alloc = l-2;
1077 : Z->_mp_size = l-2;
1078 : Z->_mp_d = LIMBS(z);
1079 : mpz_divexact_ui(Z, X, y);
1080 : mpz2GEN(z, Z); return z;
1081 : }
1082 : #else
1083 : /* assume y != 0 and the division is exact */
1084 : static GEN
1085 : diviuexact_i(GEN x, ulong y)
1086 : {
1087 : /*TODO: implement true exact division.*/
1088 : return divii(x,utoi(y));
1089 : }
1090 : #endif
1091 :
1092 : GEN
1093 39182358 : diviuexact(GEN x, ulong y)
1094 : {
1095 : GEN z;
1096 39182358 : if (!signe(x)) return gen_0;
1097 38053782 : z = diviuexact_i(x, y);
1098 38052178 : if (lgefint(z) == 2) pari_err_OP("exact division", x, utoi(y));
1099 38052239 : return z;
1100 : }
1101 :
1102 : /* Find z such that x=y*z, knowing that y | x (unchecked) */
1103 : GEN
1104 525661274 : diviiexact(GEN x, GEN y)
1105 : {
1106 : GEN z;
1107 525661274 : if (!signe(y)) pari_err_INV("diviiexact",y);
1108 525814321 : if (!signe(x)) return gen_0;
1109 433433687 : if (lgefint(y) == 3)
1110 : {
1111 375889606 : z = diviuexact_i(x, y[2]);
1112 375512520 : if (signe(y) < 0) togglesign(z);
1113 : }
1114 : else
1115 : {
1116 57544081 : long l = lgefint(x);
1117 : mpz_t X, Y, Z;
1118 57544081 : z = cgeti(l);
1119 57561531 : GEN2mpz(X, x);
1120 57561474 : GEN2mpz(Y, y);
1121 57561358 : Z->_mp_alloc = l-2;
1122 57561358 : Z->_mp_size = l-2;
1123 57561358 : Z->_mp_d = LIMBS(z);
1124 57561358 : mpz_divexact(Z, X, Y);
1125 57562375 : mpz2GEN(z, Z);
1126 : }
1127 433074868 : if (lgefint(z) == 2) pari_err_OP("exact division", x, y);
1128 433061830 : return z;
1129 : }
1130 :
1131 : /* assume yz != and yz | x */
1132 : GEN
1133 200486 : diviuuexact(GEN x, ulong y, ulong z)
1134 : {
1135 : long tmp[4];
1136 : ulong t;
1137 : LOCAL_HIREMAINDER;
1138 200486 : t = mulll(y, z);
1139 200486 : if (!hiremainder) return diviuexact(x, t);
1140 2 : tmp[0] = evaltyp(t_INT)|_evallg(4);
1141 2 : tmp[1] = evalsigne(1)|evallgefint(4);
1142 2 : tmp[2] = t;
1143 2 : tmp[3] = hiremainder;
1144 2 : return diviiexact(x, tmp);
1145 : }
1146 :
1147 : /********************************************************************/
1148 : /** **/
1149 : /** INTEGER MULTIPLICATION **/
1150 : /** **/
1151 : /********************************************************************/
1152 :
1153 : /* nx >= ny = num. of digits of x, y (not GEN, see mulii) */
1154 : GEN
1155 5921277531 : muliispec(GEN x, GEN y, long nx, long ny)
1156 : {
1157 : GEN zd;
1158 : long lz;
1159 : ulong hi;
1160 :
1161 5921277531 : if (nx < ny) swapspec(x,y, nx,ny);
1162 5921277531 : if (!ny) return gen_0;
1163 5921277531 : if (ny == 1) return muluispec((ulong)*y, x, nx);
1164 :
1165 1048559262 : lz = nx+ny+2;
1166 1048559262 : zd = cgeti(lz);
1167 1052121950 : hi = mpn_mul(LIMBS(zd), (mp_limb_t *)x, nx, (mp_limb_t *)y, ny);
1168 1059102883 : if (!hi) lz--;
1169 : /*else zd[lz-1]=hi; GH tell me it is not necessary.*/
1170 :
1171 1059102883 : zd[1] = evalsigne(1) | evallgefint(lz);
1172 1059102883 : return zd;
1173 : }
1174 : GEN
1175 222711 : muluui(ulong x, ulong y, GEN z)
1176 : {
1177 222711 : long t, s = signe(z);
1178 : GEN r;
1179 : LOCAL_HIREMAINDER;
1180 :
1181 222711 : if (!x || !y || !signe(z)) return gen_0;
1182 222326 : t = mulll(x,y);
1183 222326 : if (!hiremainder)
1184 222334 : r = muluispec(t, z+2, lgefint(z)-2);
1185 : else
1186 : {
1187 : long tmp[2];
1188 0 : tmp[1] = hiremainder;
1189 0 : tmp[0] = t;
1190 0 : r = muliispec(z+2,tmp, lgefint(z)-2, 2);
1191 : }
1192 222314 : setsigne(r,s); return r;
1193 : }
1194 :
1195 : GEN
1196 1018894515 : sqrispec(GEN x, long nx)
1197 : {
1198 : GEN zd;
1199 : long lz;
1200 :
1201 1018894515 : if (!nx) return gen_0;
1202 482405479 : if (nx==1) return sqru(*x);
1203 :
1204 273259644 : lz = (nx<<1)+2;
1205 273259644 : zd = cgeti(lz);
1206 : #ifdef mpn_sqr
1207 270365980 : mpn_sqr(LIMBS(zd), (mp_limb_t *)x, nx);
1208 : #else
1209 : mpn_mul_n(LIMBS(zd), (mp_limb_t *)x, (mp_limb_t *)x, nx);
1210 : #endif
1211 273810760 : if (zd[lz-1]==0) lz--;
1212 :
1213 273810760 : zd[1] = evalsigne(1) | evallgefint(lz);
1214 273810760 : return zd;
1215 : }
1216 :
1217 : INLINE GEN
1218 41415537 : sqrispec_mirror(GEN x, long nx)
1219 : {
1220 41415537 : GEN cx=new_chunk(nx);
1221 : GEN z;
1222 41374997 : xmpn_mirrorcopy((mp_limb_t *)cx,(mp_limb_t *)x,nx);
1223 41471735 : z=sqrispec(cx, nx);
1224 41536647 : xmpn_mirror(LIMBS(z), NLIMBS(z));
1225 41536255 : return z;
1226 : }
1227 :
1228 : /* leaves garbage on the stack. */
1229 : INLINE GEN
1230 85236796 : muliispec_mirror(GEN x, GEN y, long nx, long ny)
1231 : {
1232 : GEN cx, cy, z;
1233 85236796 : long s = 0;
1234 116366207 : while (nx && x[nx-1]==0) { nx--; s++; }
1235 122975917 : while (ny && y[ny-1]==0) { ny--; s++; }
1236 85236796 : cx=new_chunk(nx); cy=new_chunk(ny);
1237 84722439 : xmpn_mirrorcopy((mp_limb_t *)cx,(mp_limb_t *)x,nx);
1238 85588912 : xmpn_mirrorcopy((mp_limb_t *)cy,(mp_limb_t *)y,ny);
1239 86110365 : z = nx>=ny ? muliispec(cx, cy, nx, ny): muliispec(cy, cx, ny, nx);
1240 86176558 : if (s)
1241 : {
1242 7855789 : long i, lz = lgefint(z) + s;
1243 7855789 : (void)new_chunk(s);
1244 7855784 : z -= s;
1245 76724312 : for (i=0; i<s; i++) z[2+i]=0;
1246 7855784 : z[1] = evalsigne(1) | evallgefint(lz);
1247 7855784 : z[0] = evaltyp(t_INT) | evallg(lz);
1248 : }
1249 86176554 : xmpn_mirror(LIMBS(z), NLIMBS(z));
1250 86657612 : return z;
1251 : }
1252 :
1253 : /* x % (2^n), assuming n >= 0 */
1254 : GEN
1255 37409706 : remi2n(GEN x, long n)
1256 : {
1257 : ulong hi;
1258 37409706 : long l, k, lx, ly, sx = signe(x);
1259 : GEN z, xd, zd;
1260 :
1261 37409706 : if (!sx || !n) return gen_0;
1262 :
1263 37085054 : k = dvmdsBIL(n, &l);
1264 37088083 : lx = lgefint(x);
1265 37088083 : if (lx < k+3) return icopy(x);
1266 :
1267 36256211 : xd = x + (2 + k);
1268 : /* x = |k|...|1|#|... : copy the last l bits of # and the first k words
1269 : * ^--- initial xd */
1270 36256211 : hi = ((ulong)*xd) & ((1UL<<l)-1); /* last l bits of # = top bits of result */
1271 36256211 : if (!hi)
1272 : { /* strip leading zeroes from result */
1273 4117500 : xd--; while (k && !*xd) { k--; xd--; }
1274 3938357 : if (!k) return gen_0;
1275 2064217 : ly = k+2;
1276 : }
1277 : else
1278 32317854 : ly = k+3;
1279 :
1280 34382071 : zd = z = cgeti(ly);
1281 34348277 : *++zd = evalsigne(sx) | evallgefint(ly);
1282 481873232 : xd = x+1; for ( ;k; k--) *++zd = *++xd;
1283 34348277 : if (hi) *++zd = hi;
1284 34348277 : return z;
1285 : }
1286 :
1287 : /********************************************************************/
1288 : /** **/
1289 : /** INTEGER SQUARE ROOT **/
1290 : /** **/
1291 : /********************************************************************/
1292 :
1293 : /* Return S (and set R) s.t S^2 + R = N, 0 <= R <= 2S.
1294 : * As for dvmdii, R is last on stack and guaranteed to be gen_0 in case the
1295 : * remainder is 0. R = NULL is allowed. */
1296 : GEN
1297 5114746 : sqrtremi(GEN a, GEN *r)
1298 : {
1299 5114746 : long l, na = NLIMBS(a);
1300 : mp_size_t nr;
1301 : GEN S;
1302 5114746 : if (!na) {
1303 724 : if (r) *r = gen_0;
1304 724 : return gen_0;
1305 : }
1306 5114022 : l = (na + 5) >> 1; /* 2 + ceil(na/2) */
1307 5114022 : S = cgetipos(l);
1308 5113993 : if (r) {
1309 1308771 : GEN R = cgeti(2 + na);
1310 1308771 : nr = mpn_sqrtrem(LIMBS(S), LIMBS(R), LIMBS(a), na);
1311 1308772 : if (nr) R[1] = evalsigne(1) | evallgefint(nr+2);
1312 25117 : else { set_avma((pari_sp)S); R = gen_0; }
1313 1308772 : *r = R;
1314 : }
1315 : else
1316 3805222 : (void)mpn_sqrtrem(LIMBS(S), NULL, LIMBS(a), na);
1317 5113992 : return S;
1318 : }
1319 :
1320 : /* compute sqrt(|a|), assuming a != 0 */
1321 : GEN
1322 125621563 : sqrtr_abs(GEN a)
1323 : {
1324 : GEN res;
1325 : mp_limb_t *b, *c;
1326 125621563 : long l = RNLIMBS(a), e = expo(a), er = e>>1;
1327 : long n;
1328 125621563 : res = cgetg(2 + l, t_REAL);
1329 125547525 : res[1] = evalsigne(1) | evalexpo(er);
1330 125616903 : if (e&1)
1331 : {
1332 52888258 : b = (mp_limb_t *) new_chunk(l<<1);
1333 52873772 : xmpn_zero(b,l);
1334 52874826 : xmpn_mirrorcopy(b+l, RLIMBS(a), l);
1335 52885691 : c = (mp_limb_t *) new_chunk(l);
1336 52879475 : n = mpn_sqrtrem(c,b,b,l<<1); /* c <- sqrt; b <- rem */
1337 52911723 : if (n>l || (n==l && mpn_cmp(b,c,l) > 0)) mpn_add_1(c,c,l,1);
1338 : }
1339 : else
1340 : {
1341 : ulong u;
1342 72728645 : b = (mp_limb_t *) mantissa2nr(a,-1);
1343 72758868 : b[1] = uel(a,l+1)<<(BITS_IN_LONG-1);
1344 72758868 : b = (mp_limb_t *) new_chunk(l);
1345 72739248 : xmpn_zero(b,l+1); /* overwrites the former b[0] */
1346 72741953 : c = (mp_limb_t *) new_chunk(l + 1);
1347 72709699 : n = mpn_sqrtrem(c,b,b,(l<<1)+2); /* c <- sqrt; b <- rem */
1348 72796755 : u = (ulong)*c++;
1349 72796755 : if ( u&HIGHBIT || (u == ~HIGHBIT &&
1350 0 : (n>l || (n==l && mpn_cmp(b,c,l)>0))))
1351 35874054 : mpn_add_1(c,c,l,1);
1352 : }
1353 125717295 : xmpn_mirrorcopy(RLIMBS(res),c,l);
1354 125689989 : return gc_const((pari_sp)res, res);
1355 : }
1356 :
1357 : /* Normalize a nonnegative integer */
1358 : GEN
1359 307115387 : int_normalize(GEN x, long known_zero_words)
1360 : {
1361 307115387 : long i = lgefint(x) - 1 - known_zero_words;
1362 2772965691 : for ( ; i > 1; i--)
1363 2720831759 : if (x[i]) { setlgefint(x, i+1); return x; }
1364 52133932 : x[1] = evalsigne(0) | evallgefint(2); return x;
1365 : }
1366 :
1367 : /********************************************************************
1368 : ** **
1369 : ** Base Conversion **
1370 : ** **
1371 : ********************************************************************/
1372 :
1373 : ulong *
1374 438559 : convi(GEN x, long *l)
1375 : {
1376 438559 : long n = nchar2nlong(2 + (long)(NLIMBS(x) * (BITS_IN_LONG * LOG10_2)));
1377 438559 : GEN str = cgetg(n+1, t_VECSMALL);
1378 438559 : unsigned char *res = (unsigned char*) GSTR(str);
1379 438559 : long llz = mpn_get_str(res, 10, LIMBS(icopy(x)), NLIMBS(x));
1380 : long lz;
1381 : ulong *z;
1382 : long i, j;
1383 : unsigned char *t;
1384 438559 : while (!*res) {res++; llz--;} /*Strip leading zeros*/
1385 438559 : lz = (8+llz)/9;
1386 438559 : z = (ulong*)new_chunk(1+lz);
1387 438559 : t=res+llz+9;
1388 869785 : for(i=0;i<llz-8;i+=9)
1389 : {
1390 : ulong s;
1391 431226 : t-=18;
1392 431226 : s=*t++;
1393 3881034 : for (j=1; j<9;j++)
1394 3449808 : s=10*s+*t++;
1395 431226 : *z++=s;
1396 : }
1397 438559 : if (i<llz)
1398 : {
1399 434608 : unsigned char *t = res;
1400 434608 : ulong s=*t++;
1401 1228707 : for (j=i+1; j<llz;j++)
1402 794099 : s=10*s+*t++;
1403 434608 : *z++=s;
1404 : }
1405 438559 : *l = lz;
1406 438559 : return z;
1407 : }
|