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 1735631 : static void pari_gmp_free(void *ptr, size_t old_size){
52 1735631 : (void)old_size; pari_free(ptr);
53 1735631 : }
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 1088 : pari_kernel_init(void)
61 : {
62 1088 : mp_get_memory_functions (&old_gmp_malloc, &old_gmp_realloc, &old_gmp_free);
63 1088 : mp_set_memory_functions((void *(*)(size_t)) pari_malloc, pari_gmp_realloc, pari_gmp_free);
64 1088 : }
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 1080 : 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 1080 : mp_get_memory_functions (&new_gmp_malloc, &new_gmp_realloc, &new_gmp_free);
83 1080 : if (new_gmp_malloc==pari_malloc) new_gmp_malloc = old_gmp_malloc;
84 1080 : if (new_gmp_realloc==pari_gmp_realloc) new_gmp_realloc = old_gmp_realloc;
85 1080 : if (new_gmp_free==pari_gmp_free) new_gmp_free = old_gmp_free;
86 1080 : mp_set_memory_functions(new_gmp_malloc, new_gmp_realloc, new_gmp_free);
87 1080 : }
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 6870591 : xmpn_copy(mp_limb_t *x, mp_limb_t *y, long n)
97 : {
98 56261946 : while (--n >= 0) x[n]=y[n];
99 6870591 : }
100 :
101 : INLINE void
102 581812796 : xmpn_mirror(mp_limb_t *x, long n)
103 : {
104 : long i;
105 3848270902 : for(i=0;i<(n>>1);i++)
106 : {
107 3266458106 : ulong m=x[i];
108 3266458106 : x[i]=x[n-1-i];
109 3266458106 : x[n-1-i]=m;
110 : }
111 581812796 : }
112 :
113 : INLINE void
114 710964349 : xmpn_mirrorcopy(mp_limb_t *z, mp_limb_t *x, long n)
115 : {
116 : long i;
117 9767503039 : for(i=0;i<n;i++)
118 9056538690 : z[i]=x[n-1-i];
119 710964349 : }
120 :
121 : INLINE void
122 235407136 : xmpn_zero(mp_ptr x, mp_size_t n)
123 : {
124 2052500911 : while (--n >= 0) x[n]=0;
125 235407136 : }
126 :
127 : INLINE GEN
128 40943020 : icopy_ef(GEN x, long l)
129 : {
130 40943020 : long lx = lgefint(x);
131 40943020 : const GEN y = cgeti(l);
132 :
133 290319896 : while (--lx > 0) y[lx]=x[lx];
134 40941528 : 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 ordre to facilitate splitting: no
140 : * need to reintroduce codewords ]
141 : * Use speci(a,na) to visualize the corresponding GEN.
142 : */
143 :
144 : /***********************************************************************/
145 : /** **/
146 : /** ADDITION / SUBTRACTION **/
147 : /** **/
148 : /***********************************************************************/
149 :
150 : GEN
151 2997416 : setloop(GEN a)
152 : {
153 2997416 : pari_sp av = avma - 2 * sizeof(long);
154 2997416 : (void)cgetg(lgefint(a) + 3, t_VECSMALL);
155 2997416 : return icopy_avma(a, av); /* two cells of extra space after a */
156 : }
157 :
158 : /* we had a = setloop(?), then some incloops. Reset a to b */
159 : GEN
160 174328 : resetloop(GEN a, GEN b) {
161 174328 : a[0] = evaltyp(t_INT) | evallg(lgefint(b));
162 174328 : affii(b, a); return a;
163 : }
164 :
165 : /* assume a > 0, initialized by setloop. Do a++ */
166 : static GEN
167 98878835 : incpos(GEN a)
168 : {
169 98878835 : long i, l = lgefint(a);
170 98878840 : for (i=2; i<l; i++)
171 98881202 : if (++uel(a,i)) return a;
172 3 : a[l] = 1; l++;
173 3 : a[0]=evaltyp(t_INT) | _evallg(l);
174 3 : a[1]=evalsigne(1) | evallgefint(l);
175 3 : return a;
176 : }
177 :
178 : /* assume a < 0, initialized by setloop. Do a++ */
179 : static GEN
180 66652 : incneg(GEN a)
181 : {
182 66652 : long i, l = lgefint(a)-1;
183 66652 : if (uel(a,2)--)
184 : {
185 66648 : if (!a[l]) /* implies l = 2 */
186 : {
187 1976 : a[0] = evaltyp(t_INT) | _evallg(2);
188 1976 : a[1] = evalsigne(0) | evallgefint(2);
189 : }
190 66648 : return a;
191 : }
192 5 : for (i=3; i<=l; i++)
193 5 : if (uel(a,i)--) break;
194 4 : if (!a[l])
195 : {
196 4 : a[0] = evaltyp(t_INT) | _evallg(l);
197 4 : a[1] = evalsigne(-1) | evallgefint(l);
198 : }
199 4 : return a;
200 : }
201 :
202 : /* assume a initialized by setloop. Do a++ */
203 : GEN
204 99284033 : incloop(GEN a)
205 : {
206 99284033 : switch(signe(a))
207 : {
208 336616 : case 0:
209 336616 : a[0]=evaltyp(t_INT) | _evallg(3);
210 336616 : a[1]=evalsigne(1) | evallgefint(3);
211 336616 : a[2]=1; return a;
212 66652 : case -1: return incneg(a);
213 98880765 : default: return incpos(a);
214 : }
215 : }
216 :
217 : INLINE GEN
218 2579118256 : adduispec(ulong s, GEN x, long nx)
219 : {
220 : GEN zd;
221 : long lz;
222 :
223 2579118256 : if (nx == 1) return adduu(uel(x,0), s);
224 714970494 : lz = nx+3; zd = cgeti(lz);
225 717985451 : if (mpn_add_1(LIMBS(zd),(mp_limb_t *)x,nx,s))
226 5009634 : zd[lz-1]=1;
227 : else
228 712977060 : lz--;
229 717986694 : zd[1] = evalsigne(1) | evallgefint(lz);
230 717986694 : return zd;
231 : }
232 :
233 : GEN
234 580702061 : adduispec_offset(ulong s, GEN x, long offset, long nx)
235 : {
236 580702061 : GEN xd=x+2+offset;
237 806335883 : while (nx && *(xd+nx-1)==0) nx--;
238 580702061 : if (!nx) return utoi(s);
239 536053609 : return adduispec(s,xd,nx);
240 : }
241 :
242 : INLINE GEN
243 3255942127 : addiispec(GEN x, GEN y, long nx, long ny)
244 : {
245 : GEN zd;
246 : long lz;
247 :
248 3255942127 : if (nx < ny) swapspec(x,y, nx,ny);
249 3255942127 : if (ny == 1) return adduispec(*y,x,nx);
250 1302066806 : lz = nx+3; zd = cgeti(lz);
251 :
252 1302402114 : if (mpn_add(LIMBS(zd),(mp_limb_t *)x,nx,(mp_limb_t *)y,ny))
253 27960166 : zd[lz-1]=1;
254 : else
255 1274792696 : lz--;
256 :
257 1302752862 : zd[1] = evalsigne(1) | evallgefint(lz);
258 1302752862 : return zd;
259 : }
260 :
261 : /* assume x >= y */
262 : INLINE GEN
263 1718825161 : subiuspec(GEN x, ulong s, long nx)
264 : {
265 : GEN zd;
266 : long lz;
267 :
268 1718825161 : if (nx == 1) return utoi(x[0] - s);
269 :
270 240320551 : lz = nx + 2; zd = cgeti(lz);
271 240831892 : mpn_sub_1 (LIMBS(zd), (mp_limb_t *)x, nx, s);
272 240831065 : if (! zd[lz - 1]) { --lz; }
273 :
274 240831065 : zd[1] = evalsigne(1) | evallgefint(lz);
275 240831065 : return zd;
276 : }
277 :
278 : /* assume x > y */
279 : INLINE GEN
280 2943886298 : subiispec(GEN x, GEN y, long nx, long ny)
281 : {
282 : GEN zd;
283 : long lz;
284 2943886298 : if (ny==1) return subiuspec(x,*y,nx);
285 1254943727 : lz = nx+2; zd = cgeti(lz);
286 :
287 1253420658 : mpn_sub (LIMBS(zd), (mp_limb_t *)x, nx, (mp_limb_t *)y, ny);
288 1722821047 : while (lz >= 3 && zd[lz - 1] == 0) { lz--; }
289 :
290 1253636935 : zd[1] = evalsigne(1) | evallgefint(lz);
291 1253636935 : return zd;
292 : }
293 :
294 : static void
295 519933416 : roundr_up_ip(GEN x, long l)
296 : {
297 519933416 : long i = l;
298 : for(;;)
299 : {
300 521739691 : if (++((ulong*)x)[--i]) break;
301 2166439 : if (i == 2) { x[2] = HIGHBIT; shiftr_inplace(x, 1); break; }
302 : }
303 520009808 : }
304 :
305 : void
306 399694298 : affir(GEN x, GEN y)
307 : {
308 399694298 : const long s = signe(x), ly = lg(y);
309 : long lx, sh, i;
310 :
311 399694298 : if (!s)
312 : {
313 41392005 : y[1] = evalexpo(-bit_accuracy(ly));
314 41389901 : return;
315 : }
316 358302293 : lx = lgefint(x); sh = bfffo(*int_MSW(x));
317 358302293 : y[1] = evalsigne(s) | evalexpo(bit_accuracy(lx)-sh-1);
318 358482742 : if (sh) {
319 350986177 : if (lx <= ly)
320 : {
321 951623340 : for (i=lx; i<ly; i++) y[i]=0;
322 247157390 : mpn_lshift(LIMBS(y),LIMBS(x),lx-2,sh);
323 247244680 : xmpn_mirror(LIMBS(y),lx-2);
324 247545729 : return;
325 : }
326 103828787 : mpn_lshift(LIMBS(y),LIMBS(x)+lx-ly,ly-2,sh);
327 103827157 : uel(y,2) |= uel(x,lx-ly+1) >> (BITS_IN_LONG-sh);
328 103827157 : xmpn_mirror(LIMBS(y),ly-2);
329 : /* lx > ly: round properly */
330 103828675 : if ((uel(x,lx-ly+1)<<sh) & HIGHBIT) roundr_up_ip(y, ly);
331 : }
332 : else {
333 7496565 : GEN xd=int_MSW(x);
334 7496565 : if (lx <= ly)
335 : {
336 9371554 : for (i=2; i<lx; i++,xd=int_precW(xd)) y[i]=*xd;
337 5105136 : for ( ; i<ly; i++) y[i]=0;
338 2348130 : return;
339 : }
340 14637805 : for (i=2; i<ly; i++,xd=int_precW(xd)) y[i]=*xd;
341 : /* lx > ly: round properly */
342 5148435 : if (uel(x,lx-ly+1) & HIGHBIT) roundr_up_ip(y, ly);
343 : }
344 : }
345 :
346 : INLINE GEN
347 699107283 : shiftispec(GEN x, long nx, long n)
348 : {
349 : long ny,m;
350 : GEN yd, y;
351 :
352 699107283 : if (!n) return icopyspec(x, nx);
353 :
354 670241465 : if (n > 0)
355 : {
356 392495826 : long d = dvmdsBIL(n, &m);
357 : long i;
358 :
359 392389723 : ny = nx + d + (m!=0);
360 392389723 : y = cgeti(ny + 2); yd = y + 2;
361 544959190 : for (i=0; i<d; i++) yd[i] = 0;
362 :
363 391544929 : if (!m) xmpn_copy((mp_limb_t *) (yd + d), (mp_limb_t *) x, nx);
364 : else
365 : {
366 390009578 : ulong carryd = mpn_lshift((mp_limb_t *) (yd + d), (mp_limb_t *) x, nx, m);
367 390091784 : if (carryd) yd[ny - 1] = carryd;
368 366940355 : else ny--;
369 : }
370 : }
371 : else
372 : {
373 277745639 : long d = dvmdsBIL(-n, &m);
374 :
375 279632479 : ny = nx - d;
376 279632479 : if (ny < 1) return gen_0;
377 276740547 : y = cgeti(ny + 2); yd = y + 2;
378 :
379 276484921 : if (!m) xmpn_copy((mp_limb_t *) yd, (mp_limb_t *) (x + d), nx - d);
380 : else
381 : {
382 271832748 : mpn_rshift((mp_limb_t *) yd, (mp_limb_t *) (x + d), nx - d, m);
383 271846581 : if (yd[ny - 1] == 0)
384 : {
385 59909678 : if (ny == 1) return gc_const((pari_sp)(yd + 1), gen_0);
386 50426429 : ny--;
387 : }
388 : }
389 : }
390 656828350 : y[1] = evalsigne(1)|evallgefint(ny + 2);
391 656828350 : return y;
392 : }
393 :
394 : GEN
395 136975092 : mantissa2nr(GEN x, long n)
396 : {
397 136975092 : long ly, i, m, s = signe(x), lx = lg(x);
398 : GEN y;
399 136975092 : if (!s) return gen_0;
400 136973741 : if (!n)
401 : {
402 30173589 : y = cgeti(lx);
403 30170565 : y[1] = evalsigne(s) | evallgefint(lx);
404 30170565 : xmpn_mirrorcopy(LIMBS(y),RLIMBS(x),lx-2);
405 30170267 : return y;
406 : }
407 106800152 : if (n > 0)
408 : {
409 217544 : GEN z = (GEN)avma;
410 217544 : long d = dvmdsBIL(n, &m);
411 :
412 217544 : ly = lx+d; y = new_chunk(ly);
413 552196 : for ( ; d; d--) *--z = 0;
414 221920 : if (!m) for (i=2; i<lx; i++) y[i]=x[i];
415 : else
416 : {
417 216127 : const ulong sh = BITS_IN_LONG - m;
418 216127 : shift_left(y,x, 2,lx-1, 0,m);
419 216127 : i = uel(x,2) >> sh;
420 : /* Extend y on the left? */
421 216127 : if (i) { ly++; y = new_chunk(1); y[2] = i; }
422 : }
423 : }
424 : else
425 : {
426 106582608 : ly = lx - dvmdsBIL(-n, &m);
427 106580453 : if (ly<3) return gen_0;
428 106580453 : y = new_chunk(ly);
429 106551149 : if (m) {
430 106293202 : shift_right(y,x, 2,ly, 0,m);
431 106343239 : if (y[2] == 0)
432 : {
433 0 : if (ly==3) return gc_const((pari_sp)(y+3), gen_0);
434 0 : ly--; set_avma((pari_sp)(++y));
435 : }
436 : } else {
437 700046 : for (i=2; i<ly; i++) y[i]=x[i];
438 : }
439 : }
440 106818729 : xmpn_mirror(LIMBS(y),ly-2);
441 106860376 : y[1] = evalsigne(s)|evallgefint(ly);
442 106860376 : y[0] = evaltyp(t_INT)|evallg(ly); return y;
443 : }
444 :
445 : GEN
446 3547949 : truncr(GEN x)
447 : {
448 : long s, e, d, m, i;
449 : GEN y;
450 3547949 : if ((s=signe(x)) == 0 || (e=expo(x)) < 0) return gen_0;
451 1529720 : d = nbits2lg(e+1); m = remsBIL(e);
452 1529705 : if (d > lg(x)) pari_err_PREC( "truncr (precision loss in truncation)");
453 :
454 1529701 : y=cgeti(d); y[1] = evalsigne(s) | evallgefint(d);
455 1529633 : if (++m == BITS_IN_LONG)
456 95929 : for (i=2; i<d; i++) y[d-i+1]=x[i];
457 : else
458 : {
459 1481922 : GEN z=cgeti(d);
460 3030466 : for (i=2; i<d; i++) z[d-i+1]=x[i];
461 1481814 : mpn_rshift(LIMBS(y),LIMBS(z),d-2,BITS_IN_LONG-m);
462 1481817 : set_avma((pari_sp)y);
463 : }
464 1529512 : return y;
465 : }
466 :
467 : /* integral part */
468 : GEN
469 6979807 : floorr(GEN x)
470 : {
471 : long e, d, m, i, lx;
472 : GEN y;
473 6979807 : if (signe(x) >= 0) return truncr(x);
474 4198235 : if ((e=expo(x)) < 0) return gen_m1;
475 3519645 : d = nbits2lg(e+1); m = remsBIL(e);
476 3516881 : lx=lg(x); if (d>lx) pari_err_PREC( "floorr (precision loss in truncation)");
477 3516881 : y = cgeti(d+1);
478 3507752 : if (++m == BITS_IN_LONG)
479 : {
480 3032 : for (i=2; i<d; i++) y[d-i+1]=x[i];
481 1447 : i=d; while (i<lx && !x[i]) i++;
482 903 : if (i==lx) goto END;
483 : }
484 : else
485 : {
486 3506849 : GEN z=cgeti(d);
487 7841647 : for (i=2; i<d; i++) z[d-i+1]=x[i];
488 3492695 : mpn_rshift(LIMBS(y),LIMBS(z),d-2,BITS_IN_LONG-m);
489 3493324 : if (uel(x,d-1)<<m == 0)
490 : {
491 516856 : i=d; while (i<lx && !x[i]) i++;
492 117813 : if (i==lx) goto END;
493 : }
494 : }
495 3419182 : if (mpn_add_1(LIMBS(y),LIMBS(y),d-2,1))
496 0 : y[d++]=1;
497 3419279 : END:
498 3494324 : y[1] = evalsigne(-1) | evallgefint(d);
499 3494324 : return y;
500 : }
501 :
502 : INLINE int
503 3816092491 : cmpiispec(GEN x, GEN y, long lx, long ly)
504 : {
505 3816092491 : if (lx < ly) return -1;
506 3527973062 : if (lx > ly) return 1;
507 3378565127 : return mpn_cmp((mp_limb_t*)x,(mp_limb_t*)y, lx);
508 : }
509 :
510 : INLINE int
511 272728078 : equaliispec(GEN x, GEN y, long lx, long ly)
512 : {
513 272728078 : if (lx != ly) return 0;
514 272590517 : return !mpn_cmp((mp_limb_t*)x,(mp_limb_t*)y, lx);
515 : }
516 :
517 : /***********************************************************************/
518 : /** **/
519 : /** MULTIPLICATION **/
520 : /** **/
521 : /***********************************************************************/
522 : /* assume ny > 0 */
523 : INLINE GEN
524 5431906501 : muluispec(ulong x, GEN y, long ny)
525 : {
526 5431906501 : if (ny == 1)
527 4340252804 : return muluu(x, *y);
528 : else
529 : {
530 1091653697 : long lz = ny+3;
531 1091653697 : GEN z = cgeti(lz);
532 1101071461 : ulong hi = mpn_mul_1 (LIMBS(z), (mp_limb_t *)y, ny, x);
533 1102408702 : if (hi) { z[lz - 1] = hi; } else lz--;
534 1102408702 : z[1] = evalsigne(1) | evallgefint(lz);
535 1102408702 : return z;
536 : }
537 : }
538 :
539 : /* a + b*|y| */
540 : GEN
541 0 : addumului(ulong a, ulong b, GEN y)
542 : {
543 : GEN z;
544 : long i, lz;
545 : ulong hi;
546 0 : if (!b || !signe(y)) return utoi(a);
547 0 : lz = lgefint(y)+1;
548 0 : z = cgeti(lz);
549 0 : z[2]=a;
550 0 : for(i=3;i<lz;i++) z[i]=0;
551 0 : hi=mpn_addmul_1(LIMBS(z), LIMBS(y), NLIMBS(y), b);
552 0 : if (hi) z[lz-1]=hi; else lz--;
553 0 : z[1] = evalsigne(1) | evallgefint(lz);
554 0 : return gc_const((pari_sp)z, z);
555 : }
556 :
557 : /***********************************************************************/
558 : /** **/
559 : /** DIVISION **/
560 : /** **/
561 : /***********************************************************************/
562 :
563 : ulong
564 1286738803 : umodiu(GEN y, ulong x)
565 : {
566 1286738803 : long sy=signe(y);
567 : ulong hi;
568 1286738803 : if (!x) pari_err_INV("umodiu",gen_0);
569 1287607583 : if (!sy) return 0;
570 895749455 : hi = mpn_mod_1(LIMBS(y),NLIMBS(y),x);
571 895749455 : if (!hi) return 0;
572 879452997 : return (sy > 0)? hi: x - hi;
573 : }
574 :
575 : /* return |y| \/ x */
576 : GEN
577 111061339 : absdiviu_rem(GEN y, ulong x, ulong *rem)
578 : {
579 : long ly;
580 : GEN z;
581 :
582 111061339 : if (!x) pari_err_INV("absdiviu_rem",gen_0);
583 111067636 : if (!signe(y)) { *rem = 0; return gen_0; }
584 :
585 88594474 : ly = lgefint(y);
586 88594474 : if (ly == 3 && (ulong)x > uel(y,2)) { *rem = uel(y,2); return gen_0; }
587 :
588 74017801 : z = cgeti(ly);
589 74017617 : *rem = mpn_divrem_1(LIMBS(z), 0, LIMBS(y), NLIMBS(y), x);
590 74017874 : if (z [ly - 1] == 0) ly--;
591 74017874 : z[1] = evallgefint(ly) | evalsigne(1);
592 74017874 : return z;
593 : }
594 :
595 : GEN
596 85137906 : divis_rem(GEN y, long x, long *rem)
597 : {
598 85137906 : long sy=signe(y),ly,s;
599 : GEN z;
600 :
601 85137906 : if (!x) pari_err_INV("divis_rem",gen_0);
602 85146590 : if (!sy) { *rem = 0; return gen_0; }
603 59915539 : if (x<0) { s = -sy; x = -x; } else s = sy;
604 :
605 59915539 : ly = lgefint(y);
606 59915539 : if (ly == 3 && (ulong)x > uel(y,2)) { *rem = itos(y); return gen_0; }
607 :
608 41454224 : z = cgeti(ly);
609 41448794 : *rem = mpn_divrem_1(LIMBS(z), 0, LIMBS(y), NLIMBS(y), x);
610 41449079 : if (sy<0) *rem = - *rem;
611 41449079 : if (z[ly - 1] == 0) ly--;
612 41449079 : z[1] = evallgefint(ly) | evalsigne(s);
613 41449079 : return z;
614 : }
615 :
616 : GEN
617 968390 : divis(GEN y, long x)
618 : {
619 968390 : long sy=signe(y),ly,s;
620 : GEN z;
621 :
622 968390 : if (!x) pari_err_INV("divis",gen_0);
623 968390 : if (!sy) return gen_0;
624 968342 : if (x<0) { s = -sy; x = -x; } else s=sy;
625 :
626 968342 : ly = lgefint(y);
627 968342 : if (ly == 3 && (ulong)x > uel(y,2)) return gen_0;
628 :
629 968030 : z = cgeti(ly);
630 968026 : (void)mpn_divrem_1(LIMBS(z), 0, LIMBS(y), NLIMBS(y), x);
631 968027 : if (z[ly - 1] == 0) ly--;
632 968027 : z[1] = evallgefint(ly) | evalsigne(s);
633 968027 : return z;
634 : }
635 :
636 : /* We keep llx bits of x and lly bits of y*/
637 : static GEN
638 75538838 : divrr_with_gmp(GEN x, GEN y)
639 : {
640 75538838 : long lx=RNLIMBS(x),ly=RNLIMBS(y);
641 75538838 : long lw=minss(lx,ly);
642 75539735 : long lly=minss(lw+1,ly);
643 75541303 : GEN w = cgetg(lw+2, t_REAL);
644 75520863 : long lu=lw+lly;
645 75520863 : long llx=minss(lu,lx);
646 75518424 : mp_limb_t *u=(mp_limb_t *)new_chunk(lu);
647 75500749 : mp_limb_t *z=(mp_limb_t *)new_chunk(lly);
648 : mp_limb_t *q,*r;
649 75472815 : long e=expo(x)-expo(y);
650 75472815 : long sx=signe(x),sy=signe(y);
651 75472815 : xmpn_mirrorcopy(z,RLIMBS(y),lly);
652 75495117 : xmpn_mirrorcopy(u+lu-llx,RLIMBS(x),llx);
653 75535798 : xmpn_zero(u,lu-llx);
654 75559207 : q = (mp_limb_t *)new_chunk(lw+1);
655 75546160 : r = (mp_limb_t *)new_chunk(lly);
656 :
657 75525845 : mpn_tdiv_qr(q,r,0,u,lu,z,lly);
658 :
659 : /*Round up: This is not exactly correct we should test 2*r>z*/
660 75567038 : if (uel(r,lly-1) > (uel(z,lly-1)>>1))
661 37437593 : mpn_add_1(q,q,lw+1,1);
662 :
663 75567060 : xmpn_mirrorcopy(RLIMBS(w),q,lw);
664 :
665 75565044 : if (q[lw] == 0) e--;
666 41810228 : else if (q[lw] == 1) { shift_right(w,w, 2,lw+2, 1,1); }
667 0 : else { w[2] = HIGHBIT; e++; }
668 75564067 : if (sy < 0) sx = -sx;
669 75564067 : w[1] = evalsigne(sx) | evalexpo(e);
670 75558666 : return gc_const((pari_sp)w, w);
671 : }
672 :
673 : /* We keep llx bits of x and lly bits of y*/
674 : static GEN
675 35159239 : divri_with_gmp(GEN x, GEN y)
676 : {
677 35159239 : long llx=RNLIMBS(x),ly=NLIMBS(y);
678 35159239 : long lly=minss(llx+1,ly);
679 35159465 : GEN w = cgetg(llx+2, t_REAL);
680 35154696 : long lu=llx+lly, ld=ly-lly;
681 35154696 : mp_limb_t *u=(mp_limb_t *)new_chunk(lu);
682 35151574 : mp_limb_t *z=(mp_limb_t *)new_chunk(lly);
683 : mp_limb_t *q,*r;
684 35146172 : long sh=bfffo(y[ly+1]);
685 35146172 : long e=expo(x)-expi(y);
686 35147434 : long sx=signe(x),sy=signe(y);
687 35147434 : if (sh) mpn_lshift(z,LIMBS(y)+ld,lly,sh);
688 683090 : else xmpn_copy(z,LIMBS(y)+ld,lly);
689 35149489 : xmpn_mirrorcopy(u+lu-llx,RLIMBS(x),llx);
690 35155897 : xmpn_zero(u,lu-llx);
691 35161576 : q = (mp_limb_t *)new_chunk(llx+1);
692 35159649 : r = (mp_limb_t *)new_chunk(lly);
693 :
694 35155273 : mpn_tdiv_qr(q,r,0,u,lu,z,lly);
695 :
696 : /*Round up: This is not exactly correct we should test 2*r>z*/
697 35164549 : if (uel(r,lly-1) > (uel(z,lly-1)>>1))
698 16009482 : mpn_add_1(q,q,llx+1,1);
699 :
700 35164560 : xmpn_mirrorcopy(RLIMBS(w),q,llx);
701 :
702 35164233 : if (q[llx] == 0) e--;
703 10575341 : else if (q[llx] == 1) { shift_right(w,w, 2,llx+2, 1,1); }
704 0 : else { w[2] = HIGHBIT; e++; }
705 35164115 : if (sy < 0) sx = -sx;
706 35164115 : w[1] = evalsigne(sx) | evalexpo(e);
707 35162968 : return gc_const((pari_sp)w, w);
708 : }
709 :
710 : GEN
711 150108476 : divri(GEN x, GEN y)
712 : {
713 150108476 : long s = signe(y);
714 :
715 150108476 : if (!s) pari_err_INV("divri",gen_0);
716 150108678 : if (!signe(x)) return real_0_bit(expo(x) - expi(y));
717 149878541 : if (!is_bigint(y)) {
718 114724741 : GEN z = divru(x, y[2]);
719 114725869 : if (s < 0) togglesign(z);
720 114725884 : return z;
721 : }
722 35153142 : return divri_with_gmp(x,y);
723 : }
724 :
725 : GEN
726 141334921 : divrr(GEN x, GEN y)
727 : {
728 141334921 : long sx=signe(x), sy=signe(y), lx,ly,lr,e,i,j;
729 : ulong y0,y1;
730 : GEN r, r1;
731 :
732 141334921 : if (!sy) pari_err_INV("divrr",y);
733 141345233 : e = expo(x) - expo(y);
734 141345233 : if (!sx) return real_0_bit(e);
735 140846476 : if (sy<0) sx = -sx;
736 :
737 140846476 : lx=lg(x); ly=lg(y);
738 140846476 : if (ly==3)
739 : {
740 26133116 : ulong k = x[2], l = (lx>3)? x[3]: 0;
741 : LOCAL_HIREMAINDER;
742 26133116 : if (k < uel(y,2)) e--;
743 : else
744 : {
745 8201504 : l >>= 1; if (k&1) l |= HIGHBIT;
746 8201504 : k >>= 1;
747 : }
748 26133116 : hiremainder = k; k = divll(l,y[2]);
749 26133116 : if (hiremainder > (uel(y,2) >> 1) && !++k) { k = HIGHBIT; e++; }
750 26133116 : r = cgetg(3, t_REAL);
751 26132544 : r[1] = evalsigne(sx) | evalexpo(e);
752 26130395 : r[2] = k; return r;
753 : }
754 :
755 114713360 : if (ly >= prec2lg(DIVRR_GMP_LIMIT))
756 75538896 : return divrr_with_gmp(x,y);
757 :
758 39228624 : lr = minss(lx,ly); r = new_chunk(lr);
759 39242079 : r1 = r-1;
760 133277826 : r1[1] = 0; for (i=2; i<lr; i++) r1[i]=x[i];
761 39242079 : r1[lr] = (lx>ly)? x[lr]: 0;
762 39242079 : y0 = y[2]; y1 = y[3];
763 172494112 : for (i=0; i<lr-1; i++)
764 : { /* r1 = r + (i-1), OK up to r1[2] (accesses at most r[lr]) */
765 : ulong k, qp;
766 : LOCAL_HIREMAINDER;
767 : LOCAL_OVERFLOW;
768 :
769 133252033 : if (uel(r1,1) == y0) { qp = ULONG_MAX; k = addll(y0,r1[2]); }
770 : else
771 : {
772 133006909 : if (uel(r1,1) > y0) /* can't happen if i=0 */
773 : {
774 0 : GEN y1 = y+1;
775 0 : j = lr-i; r1[j] = subll(r1[j],y1[j]);
776 0 : for (j--; j>0; j--) r1[j] = subllx(r1[j],y1[j]);
777 0 : j=i; do uel(r,--j)++; while (j && !r[j]);
778 : }
779 133006909 : hiremainder = r1[1]; overflow = 0;
780 133006909 : qp = divll(r1[2],y0); k = hiremainder;
781 : }
782 133252033 : j = lr-i+1;
783 133252033 : if (!overflow)
784 : {
785 : long k3, k4;
786 133120304 : k3 = mulll(qp,y1);
787 133120304 : if (j == 3) /* i = lr - 2 maximal, r1[3] undefined -> 0 */
788 39295970 : k4 = subll(hiremainder,k);
789 : else
790 : {
791 93824334 : k3 = subll(k3, r1[3]);
792 93824334 : k4 = subllx(hiremainder,k);
793 : }
794 170771152 : while (!overflow && k4) { qp--; k3=subll(k3,y1); k4=subllx(k4,y0); }
795 : }
796 133252033 : if (j<ly) (void)mulll(qp,y[j]); else { hiremainder = 0 ; j = ly; }
797 395309444 : for (j--; j>1; j--)
798 : {
799 262057411 : r1[j] = subll(r1[j], addmul(qp,y[j]));
800 262057411 : hiremainder += overflow;
801 : }
802 133252033 : if (uel(r1,1) != hiremainder)
803 : {
804 181731 : if (uel(r1,1) < hiremainder)
805 : {
806 181731 : qp--;
807 181731 : j = lr-i-(lr-i>=ly); r1[j] = addll(r1[j], y[j]);
808 517342 : for (j--; j>1; j--) r1[j] = addllx(r1[j], y[j]);
809 : }
810 : else
811 : {
812 0 : uel(r1,1) -= hiremainder;
813 0 : while (r1[1])
814 : {
815 0 : qp++; if (!qp) { j=i; do uel(r,--j)++; while (j && !r[j]); }
816 0 : j = lr-i-(lr-i>=ly); r1[j] = subll(r1[j],y[j]);
817 0 : for (j--; j>1; j--) r1[j] = subllx(r1[j],y[j]);
818 0 : uel(r1,1) -= overflow;
819 : }
820 : }
821 : }
822 133252033 : *++r1 = qp;
823 : }
824 : /* i = lr-1 */
825 : /* round correctly */
826 39242079 : if (uel(r1,1) > (y0>>1))
827 : {
828 19789281 : j=i; do uel(r,--j)++; while (j && !r[j]);
829 : }
830 133453547 : r1 = r-1; for (j=i; j>=2; j--) r[j]=r1[j];
831 39242079 : if (r[0] == 0) e--;
832 14144656 : else if (r[0] == 1) { shift_right(r,r, 2,lr, 1,1); }
833 : else { /* possible only when rounding up to 0x2 0x0 ... */
834 18 : r[2] = (long)HIGHBIT; e++;
835 : }
836 39241050 : r[0] = evaltyp(t_REAL)|evallg(lr);
837 39295648 : r[1] = evalsigne(sx) | evalexpo(e);
838 39285330 : return r;
839 : }
840 :
841 : /* Integer division x / y: such that sign(r) = sign(x)
842 : * if z = ONLY_REM return remainder, otherwise return quotient
843 : * if z != NULL set *z to remainder
844 : * *z is the last object on stack (and thus can be disposed of with cgiv
845 : * instead of gerepile)
846 : * If *z is zero, we put gen_0 here and no copy.
847 : * space needed: lx + ly
848 : */
849 : GEN
850 1906087603 : dvmdii(GEN x, GEN y, GEN *z)
851 : {
852 1906087603 : long sx=signe(x),sy=signe(y);
853 : long lx, ly, lq;
854 : pari_sp av;
855 : GEN r,q;
856 :
857 1906087603 : if (!sy) pari_err_INV("dvmdii",y);
858 1907180604 : if (!sx)
859 : {
860 67790038 : if (!z || z == ONLY_REM) return gen_0;
861 40547967 : *z=gen_0; return gen_0;
862 : }
863 1839390566 : lx=lgefint(x);
864 1839390566 : ly=lgefint(y); lq=lx-ly;
865 1839390566 : if (lq <= 0)
866 : {
867 1160263228 : if (lq == 0)
868 : {
869 1051696550 : long s=mpn_cmp(LIMBS(x),LIMBS(y),NLIMBS(x));
870 1051696550 : if (s>0) goto DIVIDE;
871 361617118 : if (s==0)
872 : {
873 30525190 : if (z == ONLY_REM) return gen_0;
874 20005890 : if (z) *z = gen_0;
875 20005890 : if (sx < 0) sy = -sy;
876 20005890 : return stoi(sy);
877 : }
878 : }
879 439658606 : if (z == ONLY_REM) return icopy(x);
880 12381933 : if (z) *z = icopy(x);
881 12381933 : return gen_0;
882 : }
883 679127338 : DIVIDE: /* quotient is nonzero */
884 1369206770 : av=avma; if (sx<0) sy = -sy;
885 1369206770 : if (ly==3)
886 : {
887 570595318 : ulong lq = lx;
888 : ulong si;
889 570595318 : q = cgeti(lq);
890 570186723 : si = mpn_divrem_1(LIMBS(q), 0, LIMBS(x), NLIMBS(x), y[2]);
891 570715613 : if (q[lq - 1] == 0) lq--;
892 570715613 : if (z == ONLY_REM)
893 : {
894 335164436 : if (!si) return gc_const(av, gen_0);
895 289967108 : set_avma(av); r = cgeti(3);
896 289512930 : r[1] = evalsigne(sx) | evallgefint(3);
897 289512930 : r[2] = si; return r;
898 : }
899 235551177 : q[1] = evalsigne(sy) | evallgefint(lq);
900 235551177 : if (!z) return q;
901 231454963 : if (!si) { *z=gen_0; return q; }
902 59987341 : r=cgeti(3);
903 60012356 : r[1] = evalsigne(sx) | evallgefint(3);
904 60012356 : r[2] = si; *z=r; return q;
905 : }
906 798611452 : if (z == ONLY_REM)
907 : {
908 775922342 : ulong lr = lgefint(y);
909 775922342 : ulong lq = lgefint(x)-lgefint(y)+3;
910 775922342 : GEN r = cgeti(lr);
911 770934002 : GEN q = cgeti(lq);
912 764648203 : mpn_tdiv_qr(LIMBS(q), LIMBS(r),0, LIMBS(x), NLIMBS(x), LIMBS(y), NLIMBS(y));
913 777989028 : if (!r[lr - 1])
914 : {
915 807883110 : while(lr>2 && !r[lr - 1]) lr--;
916 359392290 : if (lr == 2) return gc_const(av, gen_0); /* exact division */
917 : }
918 763262530 : r[1] = evalsigne(sx) | evallgefint(lr);
919 763262530 : return gc_const((pari_sp)r, r);
920 : }
921 : else
922 : {
923 22689110 : ulong lq = lgefint(x)-lgefint(y)+3;
924 22689110 : ulong lr = lgefint(y);
925 22689110 : GEN q = cgeti(lq);
926 27586791 : GEN r = cgeti(lr);
927 27572726 : mpn_tdiv_qr(LIMBS(q), LIMBS(r),0, LIMBS(x), NLIMBS(x), LIMBS(y), NLIMBS(y));
928 27598783 : if (q[lq - 1] == 0) lq--;
929 27598783 : q[1] = evalsigne(sy) | evallgefint(lq);
930 27598783 : if (!z) return gc_const((pari_sp)q, q);
931 23901873 : if (!r[lr - 1])
932 : {
933 36756031 : while(lr>2 && !r[lr - 1]) lr--;
934 6134780 : if (lr == 2) { *z = gen_0; return gc_const((pari_sp)q, q); } /* exact */
935 : }
936 19293712 : r[1] = evalsigne(sx) | evallgefint(lr);
937 19293712 : *z = gc_const((pari_sp)r, r); return q;
938 : }
939 : }
940 :
941 : /* Montgomery reduction.
942 : * N has k words, assume T >= 0 has less than 2k.
943 : * Return res := T / B^k mod N, where B = 2^BIL
944 : * such that 0 <= res < T/B^k + N and res has less than k words */
945 : GEN
946 36697338 : red_montgomery(GEN T, GEN N, ulong inv)
947 : {
948 : pari_sp av;
949 : GEN Te, Td, Ne, Nd, scratch;
950 36697338 : ulong i, j, m, t, d, k = NLIMBS(N);
951 : int carry;
952 : LOCAL_HIREMAINDER;
953 : LOCAL_OVERFLOW;
954 :
955 36697338 : if (k == 0) return gen_0;
956 36697338 : d = NLIMBS(T); /* <= 2*k */
957 36697338 : if (d == 0) return gen_0;
958 : #ifdef DEBUG
959 : if (d > 2*k) pari_err_BUG("red_montgomery");
960 : #endif
961 36697329 : if (k == 1)
962 : { /* as below, special cased for efficiency */
963 163341 : ulong n = uel(N,2);
964 163341 : if (d == 1) {
965 163194 : hiremainder = uel(T,2);
966 163194 : m = hiremainder * inv;
967 163194 : (void)addmul(m, n); /* t + m*n = 0 */
968 163194 : return utoi(hiremainder);
969 : } else { /* d = 2 */
970 147 : hiremainder = uel(T,2);
971 147 : m = hiremainder * inv;
972 147 : (void)addmul(m, n); /* t + m*n = 0 */
973 147 : t = addll(hiremainder, uel(T,3));
974 147 : if (overflow) t -= n; /* t > n doesn't fit in 1 word */
975 147 : return utoi(t);
976 : }
977 : }
978 : /* assume k >= 2 */
979 36533988 : av = avma; scratch = new_chunk(k<<1); /* >= k + 2: result fits */
980 :
981 : /* copy T to scratch space (pad with zeroes to 2k words) */
982 36260396 : Td = scratch;
983 36260396 : Te = T + 2;
984 526877620 : for (i=0; i < d ; i++) *Td++ = *Te++;
985 64589987 : for ( ; i < (k<<1); i++) *Td++ = 0;
986 :
987 36260396 : Te = scratch - 1; /* 1 beyond end of current T mantissa (in scratch) */
988 36260396 : Ne = N + 1; /* 1 beyond end of N mantissa */
989 :
990 36260396 : carry = 0;
991 276659511 : for (i=0; i<k; i++) /* set T := T/B nod N, k times */
992 : {
993 240399115 : Td = Te; /* one beyond end of (new) T mantissa */
994 240399115 : Nd = Ne;
995 240399115 : hiremainder = *++Td;
996 240399115 : m = hiremainder * inv; /* solve T + m N = O(B) */
997 :
998 : /* set T := (T + mN) / B */
999 240399115 : Te = Td;
1000 240399115 : (void)addmul(m, *++Nd); /* = 0 */
1001 2127460334 : for (j=1; j<k; j++)
1002 : {
1003 1887061219 : t = addll(addmul(m, *++Nd), *++Td);
1004 1887061219 : *Td = t;
1005 1887061219 : hiremainder += overflow;
1006 : }
1007 240399115 : t = addll(hiremainder, *++Td); *Td = t + carry;
1008 240399115 : carry = (overflow || (carry && *Td == 0));
1009 : }
1010 36260396 : if (carry)
1011 : { /* Td > N overflows (k+1 words), set Td := Td - N */
1012 56691 : GEN NE = N + k+1;
1013 56691 : Td = Te;
1014 56691 : Nd = Ne;
1015 56691 : t = subll(*++Td, *++Nd); *Td = t;
1016 508033 : while (Nd < NE) { t = subllx(*++Td, *++Nd); *Td = t; }
1017 : }
1018 :
1019 : /* copy result */
1020 36260396 : Td = (GEN)av - 1; /* *Td = high word of final result */
1021 39757351 : while (*Td == 0 && Te < Td) Td--; /* strip leading 0s */
1022 36260396 : k = Td - Te; if (!k) return gc_const(av, gen_0);
1023 36260396 : Td = (GEN)av - k; /* will write mantissa there */
1024 36260396 : (void)memmove(Td, Te+1, k*sizeof(long));
1025 36260396 : Td -= 2;
1026 36260396 : Td[0] = evaltyp(t_INT) | evallg(k+2);
1027 36494266 : Td[1] = evalsigne(1) | evallgefint(k+2);
1028 : #ifdef DEBUG
1029 : {
1030 : long l = NLIMBS(N), s = BITS_IN_LONG*l;
1031 : GEN R = int2n(s);
1032 : GEN res = remii(mulii(T, Fp_inv(R, N)), N);
1033 : if (k > lgefint(N)
1034 : || !equalii(remii(Td,N),res)
1035 : || cmpii(Td, addii(shifti(T, -s), N)) >= 0) pari_err_BUG("red_montgomery");
1036 : }
1037 : #endif
1038 36494266 : return gc_const((pari_sp)Td, Td);
1039 : }
1040 :
1041 : /* EXACT INTEGER DIVISION */
1042 :
1043 : /* use undocumented GMP interface */
1044 : static void
1045 114816497 : GEN2mpz(mpz_t X, GEN x)
1046 : {
1047 114816497 : long l = lgefint(x)-2;
1048 114816497 : X->_mp_alloc = l;
1049 114816497 : X->_mp_size = signe(x) > 0? l: -l;
1050 114816497 : X->_mp_d = LIMBS(x);
1051 114816497 : }
1052 : static void
1053 57409677 : mpz2GEN(GEN z, mpz_t Z)
1054 : {
1055 57409677 : long l = Z->_mp_size;
1056 57409677 : z[1] = evalsigne(l > 0? 1: -1) | evallgefint(labs(l)+2);
1057 57409677 : }
1058 :
1059 : #ifdef mpn_divexact_1
1060 : static GEN
1061 379173547 : diviuexact_i(GEN x, ulong y)
1062 : {
1063 379173547 : long l = lgefint(x);
1064 379173547 : GEN z = cgeti(l);
1065 378729952 : mpn_divexact_1(LIMBS(z), LIMBS(x), NLIMBS(x), y);
1066 378837777 : if (z[l-1] == 0) l--;
1067 378837777 : z[1] = evallgefint(l) | evalsigne(signe(x));
1068 378837777 : return z;
1069 : }
1070 : #elif 1 && !defined(_WIN64) /* mpz_divexact_ui is not LLP64 friendly */
1071 : /* assume y != 0 and the division is exact */
1072 : static GEN
1073 : diviuexact_i(GEN x, ulong y)
1074 : {
1075 : long l = lgefint(x);
1076 : GEN z = cgeti(l);
1077 : mpz_t X, Z;
1078 : GEN2mpz(X, x);
1079 : Z->_mp_alloc = l-2;
1080 : Z->_mp_size = l-2;
1081 : Z->_mp_d = LIMBS(z);
1082 : mpz_divexact_ui(Z, X, y);
1083 : mpz2GEN(z, Z); return z;
1084 : }
1085 : #else
1086 : /* assume y != 0 and the division is exact */
1087 : static GEN
1088 : diviuexact_i(GEN x, ulong y)
1089 : {
1090 : /*TODO: implement true exact division.*/
1091 : return divii(x,utoi(y));
1092 : }
1093 : #endif
1094 :
1095 : GEN
1096 31132957 : diviuexact(GEN x, ulong y)
1097 : {
1098 : GEN z;
1099 31132957 : if (!signe(x)) return gen_0;
1100 30004381 : z = diviuexact_i(x, y);
1101 30001324 : if (lgefint(z) == 2) pari_err_OP("exact division", x, utoi(y));
1102 30000990 : return z;
1103 : }
1104 :
1105 : /* Find z such that x=y*z, knowing that y | x (unchecked) */
1106 : GEN
1107 495799453 : diviiexact(GEN x, GEN y)
1108 : {
1109 : GEN z;
1110 495799453 : if (!signe(y)) pari_err_INV("diviiexact",y);
1111 495966735 : if (!signe(x)) return gen_0;
1112 406778557 : if (lgefint(y) == 3)
1113 : {
1114 349375482 : z = diviuexact_i(x, y[2]);
1115 349041385 : if (signe(y) < 0) togglesign(z);
1116 : }
1117 : else
1118 : {
1119 57403075 : long l = lgefint(x);
1120 : mpz_t X, Y, Z;
1121 57403075 : z = cgeti(l);
1122 57408453 : GEN2mpz(X, x);
1123 57408373 : GEN2mpz(Y, y);
1124 57408214 : Z->_mp_alloc = l-2;
1125 57408214 : Z->_mp_size = l-2;
1126 57408214 : Z->_mp_d = LIMBS(z);
1127 57408214 : mpz_divexact(Z, X, Y);
1128 57409705 : mpz2GEN(z, Z);
1129 : }
1130 406451037 : if (lgefint(z) == 2) pari_err_OP("exact division", x, y);
1131 406429916 : return z;
1132 : }
1133 :
1134 : /* assume yz != and yz | x */
1135 : GEN
1136 199459 : diviuuexact(GEN x, ulong y, ulong z)
1137 : {
1138 : long tmp[4];
1139 : ulong t;
1140 : LOCAL_HIREMAINDER;
1141 199459 : t = mulll(y, z);
1142 199459 : if (!hiremainder) return diviuexact(x, t);
1143 0 : tmp[0] = evaltyp(t_INT)|_evallg(4);
1144 0 : tmp[1] = evalsigne(1)|evallgefint(4);
1145 0 : tmp[2] = t;
1146 0 : tmp[3] = hiremainder;
1147 0 : return diviiexact(x, tmp);
1148 : }
1149 :
1150 : /********************************************************************/
1151 : /** **/
1152 : /** INTEGER MULTIPLICATION **/
1153 : /** **/
1154 : /********************************************************************/
1155 :
1156 : /* nx >= ny = num. of digits of x, y (not GEN, see mulii) */
1157 : GEN
1158 5765046644 : muliispec(GEN x, GEN y, long nx, long ny)
1159 : {
1160 : GEN zd;
1161 : long lz;
1162 : ulong hi;
1163 :
1164 5765046644 : if (nx < ny) swapspec(x,y, nx,ny);
1165 5765046644 : if (!ny) return gen_0;
1166 5765046644 : if (ny == 1) return muluispec((ulong)*y, x, nx);
1167 :
1168 1030902617 : lz = nx+ny+2;
1169 1030902617 : zd = cgeti(lz);
1170 1034326605 : hi = mpn_mul(LIMBS(zd), (mp_limb_t *)x, nx, (mp_limb_t *)y, ny);
1171 1041420953 : if (!hi) lz--;
1172 : /*else zd[lz-1]=hi; GH tell me it is not necessary.*/
1173 :
1174 1041420953 : zd[1] = evalsigne(1) | evallgefint(lz);
1175 1041420953 : return zd;
1176 : }
1177 : GEN
1178 221678 : muluui(ulong x, ulong y, GEN z)
1179 : {
1180 221678 : long t, s = signe(z);
1181 : GEN r;
1182 : LOCAL_HIREMAINDER;
1183 :
1184 221678 : if (!x || !y || !signe(z)) return gen_0;
1185 221298 : t = mulll(x,y);
1186 221298 : if (!hiremainder)
1187 221312 : r = muluispec(t, z+2, lgefint(z)-2);
1188 : else
1189 : {
1190 : long tmp[2];
1191 0 : tmp[1] = hiremainder;
1192 0 : tmp[0] = t;
1193 0 : r = muliispec(z+2,tmp, lgefint(z)-2, 2);
1194 : }
1195 221298 : setsigne(r,s); return r;
1196 : }
1197 :
1198 : GEN
1199 987582431 : sqrispec(GEN x, long nx)
1200 : {
1201 : GEN zd;
1202 : long lz;
1203 :
1204 987582431 : if (!nx) return gen_0;
1205 479310332 : if (nx==1) return sqru(*x);
1206 :
1207 274153278 : lz = (nx<<1)+2;
1208 274153278 : zd = cgeti(lz);
1209 : #ifdef mpn_sqr
1210 271472956 : mpn_sqr(LIMBS(zd), (mp_limb_t *)x, nx);
1211 : #else
1212 : mpn_mul_n(LIMBS(zd), (mp_limb_t *)x, (mp_limb_t *)x, nx);
1213 : #endif
1214 274914638 : if (zd[lz-1]==0) lz--;
1215 :
1216 274914638 : zd[1] = evalsigne(1) | evallgefint(lz);
1217 274914638 : return zd;
1218 : }
1219 :
1220 : INLINE GEN
1221 41356015 : sqrispec_mirror(GEN x, long nx)
1222 : {
1223 41356015 : GEN cx=new_chunk(nx);
1224 : GEN z;
1225 41317496 : xmpn_mirrorcopy((mp_limb_t *)cx,(mp_limb_t *)x,nx);
1226 41438732 : z=sqrispec(cx, nx);
1227 41494025 : xmpn_mirror(LIMBS(z), NLIMBS(z));
1228 41492134 : return z;
1229 : }
1230 :
1231 : /* leaves garbage on the stack. */
1232 : INLINE GEN
1233 83612523 : muliispec_mirror(GEN x, GEN y, long nx, long ny)
1234 : {
1235 : GEN cx, cy, z;
1236 83612523 : long s = 0;
1237 112663631 : while (nx && x[nx-1]==0) { nx--; s++; }
1238 118031024 : while (ny && y[ny-1]==0) { ny--; s++; }
1239 83612523 : cx=new_chunk(nx); cy=new_chunk(ny);
1240 83149418 : xmpn_mirrorcopy((mp_limb_t *)cx,(mp_limb_t *)x,nx);
1241 84087148 : xmpn_mirrorcopy((mp_limb_t *)cy,(mp_limb_t *)y,ny);
1242 84591067 : z = nx>=ny ? muliispec(cx, cy, nx, ny): muliispec(cy, cx, ny, nx);
1243 84683990 : if (s)
1244 : {
1245 7633845 : long i, lz = lgefint(z) + s;
1246 7633845 : (void)new_chunk(s);
1247 7633839 : z -= s;
1248 71103446 : for (i=0; i<s; i++) z[2+i]=0;
1249 7633839 : z[1] = evalsigne(1) | evallgefint(lz);
1250 7633839 : z[0] = evaltyp(t_INT) | evallg(lz);
1251 : }
1252 84683985 : xmpn_mirror(LIMBS(z), NLIMBS(z));
1253 85274307 : return z;
1254 : }
1255 :
1256 : /* x % (2^n), assuming n >= 0 */
1257 : GEN
1258 36053563 : remi2n(GEN x, long n)
1259 : {
1260 : ulong hi;
1261 36053563 : long l, k, lx, ly, sx = signe(x);
1262 : GEN z, xd, zd;
1263 :
1264 36053563 : if (!sx || !n) return gen_0;
1265 :
1266 35736423 : k = dvmdsBIL(n, &l);
1267 35745138 : lx = lgefint(x);
1268 35745138 : if (lx < k+3) return icopy(x);
1269 :
1270 34875274 : xd = x + (2 + k);
1271 : /* x = |k|...|1|#|... : copy the last l bits of # and the first k words
1272 : * ^--- initial xd */
1273 34875274 : hi = ((ulong)*xd) & ((1UL<<l)-1); /* last l bits of # = top bits of result */
1274 34875274 : if (!hi)
1275 : { /* strip leading zeroes from result */
1276 3163418 : xd--; while (k && !*xd) { k--; xd--; }
1277 2977734 : if (!k) return gen_0;
1278 2038132 : ly = k+2;
1279 : }
1280 : else
1281 31897540 : ly = k+3;
1282 :
1283 33935672 : zd = z = cgeti(ly);
1284 33897630 : *++zd = evalsigne(sx) | evallgefint(ly);
1285 499560320 : xd = x+1; for ( ;k; k--) *++zd = *++xd;
1286 33897630 : if (hi) *++zd = hi;
1287 33897630 : return z;
1288 : }
1289 :
1290 : /********************************************************************/
1291 : /** **/
1292 : /** INTEGER SQUARE ROOT **/
1293 : /** **/
1294 : /********************************************************************/
1295 :
1296 : /* Return S (and set R) s.t S^2 + R = N, 0 <= R <= 2S.
1297 : * As for dvmdii, R is last on stack and guaranteed to be gen_0 in case the
1298 : * remainder is 0. R = NULL is allowed. */
1299 : GEN
1300 5113123 : sqrtremi(GEN a, GEN *r)
1301 : {
1302 5113123 : long l, na = NLIMBS(a);
1303 : mp_size_t nr;
1304 : GEN S;
1305 5113123 : if (!na) {
1306 724 : if (r) *r = gen_0;
1307 724 : return gen_0;
1308 : }
1309 5112399 : l = (na + 5) >> 1; /* 2 + ceil(na/2) */
1310 5112399 : S = cgetipos(l);
1311 5112350 : if (r) {
1312 1309256 : GEN R = cgeti(2 + na);
1313 1309256 : nr = mpn_sqrtrem(LIMBS(S), LIMBS(R), LIMBS(a), na);
1314 1309256 : if (nr) R[1] = evalsigne(1) | evallgefint(nr+2);
1315 25628 : else { set_avma((pari_sp)S); R = gen_0; }
1316 1309256 : *r = R;
1317 : }
1318 : else
1319 3803094 : (void)mpn_sqrtrem(LIMBS(S), NULL, LIMBS(a), na);
1320 5112351 : return S;
1321 : }
1322 :
1323 : /* compute sqrt(|a|), assuming a != 0 */
1324 : GEN
1325 124940749 : sqrtr_abs(GEN a)
1326 : {
1327 : GEN res;
1328 : mp_limb_t *b, *c;
1329 124940749 : long l = RNLIMBS(a), e = expo(a), er = e>>1;
1330 : long n;
1331 124940749 : res = cgetg(2 + l, t_REAL);
1332 124851607 : res[1] = evalsigne(1) | evalexpo(er);
1333 124933854 : if (e&1)
1334 : {
1335 52503774 : b = (mp_limb_t *) new_chunk(l<<1);
1336 52491128 : xmpn_zero(b,l);
1337 52492419 : xmpn_mirrorcopy(b+l, RLIMBS(a), l);
1338 52511843 : c = (mp_limb_t *) new_chunk(l);
1339 52508091 : n = mpn_sqrtrem(c,b,b,l<<1); /* c <- sqrt; b <- rem */
1340 52538283 : if (n>l || (n==l && mpn_cmp(b,c,l) > 0)) mpn_add_1(c,c,l,1);
1341 : }
1342 : else
1343 : {
1344 : ulong u;
1345 72430080 : b = (mp_limb_t *) mantissa2nr(a,-1);
1346 72470512 : b[1] = uel(a,l+1)<<(BITS_IN_LONG-1);
1347 72470512 : b = (mp_limb_t *) new_chunk(l);
1348 72452519 : xmpn_zero(b,l+1); /* overwrites the former b[0] */
1349 72454589 : c = (mp_limb_t *) new_chunk(l + 1);
1350 72423257 : n = mpn_sqrtrem(c,b,b,(l<<1)+2); /* c <- sqrt; b <- rem */
1351 72508698 : u = (ulong)*c++;
1352 72508698 : if ( u&HIGHBIT || (u == ~HIGHBIT &&
1353 0 : (n>l || (n==l && mpn_cmp(b,c,l)>0))))
1354 35725212 : mpn_add_1(c,c,l,1);
1355 : }
1356 125054971 : xmpn_mirrorcopy(RLIMBS(res),c,l);
1357 125028281 : return gc_const((pari_sp)res, res);
1358 : }
1359 :
1360 : /* Normalize a nonnegative integer */
1361 : GEN
1362 302980427 : int_normalize(GEN x, long known_zero_words)
1363 : {
1364 302980427 : long i = lgefint(x) - 1 - known_zero_words;
1365 2198802149 : for ( ; i > 1; i--)
1366 2148555839 : if (x[i]) { setlgefint(x, i+1); return x; }
1367 50246310 : x[1] = evalsigne(0) | evallgefint(2); return x;
1368 : }
1369 :
1370 : /********************************************************************
1371 : ** **
1372 : ** Base Conversion **
1373 : ** **
1374 : ********************************************************************/
1375 :
1376 : ulong *
1377 436578 : convi(GEN x, long *l)
1378 : {
1379 436578 : long n = nchar2nlong(2 + (long)(NLIMBS(x) * (BITS_IN_LONG * LOG10_2)));
1380 436578 : GEN str = cgetg(n+1, t_VECSMALL);
1381 436578 : unsigned char *res = (unsigned char*) GSTR(str);
1382 436578 : long llz = mpn_get_str(res, 10, LIMBS(icopy(x)), NLIMBS(x));
1383 : long lz;
1384 : ulong *z;
1385 : long i, j;
1386 : unsigned char *t;
1387 436578 : while (!*res) {res++; llz--;} /*Strip leading zeros*/
1388 436578 : lz = (8+llz)/9;
1389 436578 : z = (ulong*)new_chunk(1+lz);
1390 436578 : t=res+llz+9;
1391 866072 : for(i=0;i<llz-8;i+=9)
1392 : {
1393 : ulong s;
1394 429494 : t-=18;
1395 429494 : s=*t++;
1396 3865446 : for (j=1; j<9;j++)
1397 3435952 : s=10*s+*t++;
1398 429494 : *z++=s;
1399 : }
1400 436578 : if (i<llz)
1401 : {
1402 432623 : unsigned char *t = res;
1403 432623 : ulong s=*t++;
1404 1224287 : for (j=i+1; j<llz;j++)
1405 791664 : s=10*s+*t++;
1406 432623 : *z++=s;
1407 : }
1408 436578 : *l = lz;
1409 436578 : return z;
1410 : }
|