Annotation of OpenXM_contrib/pari-2.2/src/basemath/arith2.c, Revision 1.2
1.2 ! noro 1: /* $Id: arith2.c,v 1.53 2002/09/02 21:14:43 karim Exp $
1.1 noro 2:
3: Copyright (C) 2000 The PARI group.
4:
5: This file is part of the PARI/GP package.
6:
7: PARI/GP is free software; you can redistribute it and/or modify it under the
8: terms of the GNU General Public License as published by the Free Software
9: Foundation. 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
15:
16: /*********************************************************************/
17: /** **/
18: /** ARITHMETIC FUNCTIONS **/
19: /** (second part) **/
20: /** **/
21: /*********************************************************************/
22: #include "pari.h"
23:
24: extern GEN arith_proto(long f(GEN), GEN x, int do_error);
25: extern GEN arith_proto2(long f(GEN,GEN), GEN x, GEN n);
26: extern GEN garith_proto(GEN f(GEN), GEN x, int do_error);
27: extern GEN garith_proto2gs(GEN f(GEN,long), GEN x, long y);
1.2 ! noro 28: extern GEN garith_proto3ggs(GEN f(GEN,GEN,long), GEN x, GEN y, long z);
1.1 noro 29:
30: #define sqru(i) (muluu((i),(i)))
31:
32: /***********************************************************************/
33: /** **/
34: /** PRIME NUMBERS **/
35: /** **/
36: /***********************************************************************/
37:
38: GEN
39: prime(long n)
40: {
41: byteptr p = diffptr;
1.2 ! noro 42: long prime = 0;
1.1 noro 43:
44: if (n <= 0) err(talker, "n-th prime meaningless if n = %ld",n);
45: while (n--)
46: {
1.2 ! noro 47: NEXT_PRIME_VIADIFF_CHECK(prime,p);
1.1 noro 48: }
49: return stoi(prime);
50: }
51:
52: GEN
53: pith(long n)
54: {
55: byteptr p = diffptr;
56: ulong prime = 0, res = 0;
57:
58: if (n <= 0) err(talker, "pith meaningless if n = %ld",n);
1.2 ! noro 59: if (maxprime() <= (ulong)n) err(primer1);
! 60: while (prime<=(ulong)n) {
! 61: NEXT_PRIME_VIADIFF(prime,p);
! 62: res++;
! 63: }
1.1 noro 64: return stoi(res-1);
65: }
66:
67: GEN
68: primes(long n)
69: {
70: byteptr p = diffptr;
1.2 ! noro 71: long prime = 0;
1.1 noro 72: GEN y,z;
73:
74: if (n < 0) n = 0;
75: z = y = cgetg(n+1,t_VEC);
76: while (n--)
77: {
1.2 ! noro 78: NEXT_PRIME_VIADIFF_CHECK(prime,p);
! 79: *++z = lstoi(prime);
1.1 noro 80: }
81: return y;
82: }
83:
84: /* Building/Rebuilding the diffptr table. Incorporates Ilya Zakharevich's
85: * block sweep algorithm (see pari-dev-111, 25 April 1998). The actual work
86: * is done by the following two subroutines; the user entry point is the
87: * function initprimes() below. initprimes1() is the old algorithm, called
88: * when maxnum (size) is moderate.
89: */
90: static byteptr
1.2 ! noro 91: initprimes1(ulong size, long *lenp, long *lastp)
1.1 noro 92: {
93: long k;
94: byteptr q,r,s,fin, p = (byteptr) gpmalloc(size+2);
95:
96: memset(p, 0, size + 2); fin = p + size;
97: for (r=q=p,k=1; r<=fin; )
98: {
99: do { r+=k; k+=2; r+=k; } while (*++q);
100: for (s=r; s<=fin; s+=k) *s=1;
101: }
102: r=p; *r++=2; *r++=1; /* 2 and 3 */
103: for (s=q=r-1; ; s=q)
104: {
105: do q++; while (*q);
106: if (q>fin) break;
107: *r++ = (q-s) << 1;
108: }
109: *r++=0;
110: *lenp = r - p;
111: *lastp = ((s - p) << 1) + 1;
112: #if 0
113: fprintferr("initprimes1: q = %ld, len = %ld, last = %ld\n",
114: q, *lenp, *lastp);
115: #endif
1.2 ! noro 116: return (byteptr) gprealloc(p,r-p);
1.1 noro 117: }
118:
119: #define PRIME_ARENA (200 * 1024) /* No slowdown even with 256K level-2 cache */
120:
121: /* Here's the workhorse. This is recursive, although normally the first
122: recursive call will bottom out and invoke initprimes1() at once.
123: (Not static; might conceivably be useful to someone in library mode) */
124: byteptr
1.2 ! noro 125: initprimes0(ulong maxnum, long *lenp, ulong *lastp)
1.1 noro 126: {
1.2 ! noro 127: long k, size, alloced, asize, psize, rootnum;
1.1 noro 128: byteptr q,r,s,fin, p, p1, fin1, plast, curdiff;
1.2 ! noro 129: ulong last, remains, curlow;
1.1 noro 130:
131: #if 0
132: fprintferr("initprimes0: called for maxnum = %lu\n", maxnum);
133: #endif
134: if (maxnum <= 1ul<<17) /* Arbitrary. */
135: return initprimes1(maxnum>>1, lenp, lastp);
136:
137: maxnum |= 1; /* make it odd. */
138:
139: /* Checked to be enough up to 40e6, attained at 155893 */
140: size = (long) (1.09 * maxnum/log((double)maxnum)) + 145;
141: p1 = (byteptr) gpmalloc(size);
142: rootnum = (long) sqrt((double)maxnum); /* cast it back to a long */
143: rootnum |= 1;
144: #if 0
145: fprintferr("initprimes0: rootnum = %ld\n", rootnum);
146: #endif
147: {
148: byteptr p2 = initprimes0(rootnum, &psize, &last); /* recursive call */
149: memcpy(p1, p2, psize); free(p2);
150: }
151: fin1 = p1 + psize - 1;
152: remains = (maxnum - rootnum) >> 1; /* number of odd numbers to check */
153:
154: /* ARENA_IN_ROOTS below 12: some slowdown starts to be noticable
155: * when things fit into the cache.
156: * XXX The choice of 10 gives a slowdown of 1-2% on UltraSparcII,
157: * but makes calculations even for (the current) maximum of 436273009
158: * fit into 256K cache (still common for some architectures).
159: *
160: * One may change it when small caches become uncommon, but the gain
161: * is not going to be very noticable... */
162: #define ARENA_IN_ROOTS 10
163:
164: asize = ARENA_IN_ROOTS * rootnum; /* Make % overhead negligeable. */
165: if (asize < PRIME_ARENA) asize = PRIME_ARENA;
166: if (asize > remains) asize = remains + 1;/* + room for a sentinel byte */
1.2 ! noro 167: alloced = (avma - bot < (size_t)asize>>1); /* enough room on the stack ? */
1.1 noro 168: if (alloced)
169: p = (byteptr) gpmalloc(asize);
170: else
171: p = (byteptr) bot;
172: fin = p + asize - 1; /* the 0 sentinel goes at fin. */
173: curlow = rootnum + 2; /* We know all primes up to rootnum (odd). */
174: curdiff = fin1;
175:
176: /* During each iteration p..fin-1 represents a range of odd
177: numbers. plast is a pointer which represents the last prime seen,
178: it may point before p..fin-1. */
179: plast = p - ((rootnum - last) >> 1) - 1;
180: while (remains)
181: {
182: if (asize > remains)
183: {
184: asize = remains + 1;
185: fin = p + asize - 1;
186: }
187: memset(p, 0, asize);
188: /* p corresponds to curlow. q runs over primediffs. */
1.2 ! noro 189: /* Don't care about DIFFPTR_SKIP: false positives provide no problem */
1.1 noro 190: for (q = p1+2, k = 3; q <= fin1; k += *q++)
191: {
192: /* The first odd number which is >= curlow and divisible by p
193: equals (if curlow > p)
194: the last odd number which is <= curlow + 2p - 1 and 0 (mod p)
195: which equals
196: p + the last even number which is <= curlow + p - 1 and 0 (mod p)
197: which equals
198: p + the last even number which is <= curlow + p - 2 and 0 (mod p)
199: which equals
200: p + curlow + p - 2 - (curlow + p - 2)) % 2p.
201: */
202: long k2 = k*k - curlow;
203:
204: if (k2 > 0)
205: {
206: r = p + (k2 >>= 1);
207: if (k2 > remains) break; /* Guard against an address wrap. */
208: } else
209: r = p - (((curlow+k-2) % (2*k)) >> 1) + k - 1;
210: for (s = r; s < fin; s += k) *s = 1;
211: }
212: /* now q runs over addresses corresponding to primes */
213: for (q = p; ; plast = q++)
214: {
1.2 ! noro 215: long d;
! 216:
1.1 noro 217: while (*q) q++; /* use 0-sentinel at end */
218: if (q >= fin) break;
1.2 ! noro 219: d = (q - plast) << 1;
! 220: while (d >= DIFFPTR_SKIP)
! 221: *curdiff++ = DIFFPTR_SKIP, d -= DIFFPTR_SKIP;
! 222: *curdiff++ = d;
1.1 noro 223: }
224: plast -= asize - 1;
225: remains -= asize - 1;
226: curlow += ((asize - 1)<<1);
227: } /* while (remains) */
228: last = curlow - ((p - plast) << 1);
229: *curdiff++ = 0; /* sentinel */
230: *lenp = curdiff - p1;
231: *lastp = last;
232: if (alloced) free(p);
1.2 ! noro 233: return (byteptr) gprealloc(p1, *lenp);
1.1 noro 234: }
235: #if 0 /* not yet... GN */
236: /* The diffptr table will contain at least 6548 entries (up to and including
237: the 6547th prime, 65557, and the terminal null byte), because the isprime/
238: small-factor-extraction machinery wants to depend on everything up to 65539
239: being in the table, and we might as well go to a multiple of 4 Bytes.--GN */
240:
241: void
242: init_tinyprimes_tridiv(byteptr p); /* in ifactor2.c */
243: #endif
244:
245: static ulong _maxprime = 0;
246:
247: ulong
1.2 ! noro 248: maxprime(void) { return _maxprime; }
1.1 noro 249:
250: byteptr
1.2 ! noro 251: initprimes(ulong maxnum)
1.1 noro 252: {
1.2 ! noro 253: long len;
! 254: ulong last;
1.1 noro 255: byteptr p;
1.2 ! noro 256: /* The algorithm must see the next prime beyond maxnum, whence the +512. */
! 257: /* switch to unsigned: adding the 512 _could_ wrap to a negative number. */
! 258: ulong maxnum1 = ((maxnum<65302?65302:maxnum)+512ul);
1.1 noro 259:
1.2 ! noro 260: if ((maxnum>>1) > VERYBIGINT - 1024)
! 261: err(talker, "Too large primelimit");
1.1 noro 262: p = initprimes0(maxnum1, &len, &last);
263: #if 0 /* not yet... GN */
264: static int build_the_tables = 1;
265: if (build_the_tables) { init_tinyprimes_tridiv(p); build_the_tables=0; }
266: #endif
267: _maxprime = last; return p;
268: }
269:
270: static void
271: cleanprimetab(void)
272: {
273: long i,j, lp = lg(primetab);
274:
275: for (i=j=1; i < lp; i++)
276: if (primetab[i]) primetab[j++] = primetab[i];
277: setlg(primetab,j);
278: }
279:
280: /* p is a single element or a row vector with "primes" to add to primetab.
281: * If p shares a non-trivial factor with another element in primetab, take it
282: * into account. */
283: GEN
284: addprimes(GEN p)
285: {
1.2 ! noro 286: gpmem_t av;
1.1 noro 287: long i,k,tx,lp;
288: GEN L;
289:
290: if (!p) return primetab;
291: tx = typ(p);
292: if (is_vec_t(tx))
293: {
1.2 ! noro 294: for (i=1; i < lg(p); i++) (void)addprimes((GEN) p[i]);
1.1 noro 295: return primetab;
296: }
297: if (tx != t_INT) err(typeer,"addprime");
298: if (is_pm1(p)) return primetab;
299: av = avma; i = signe(p);
300: if (i == 0) err(talker,"can't accept 0 in addprimes");
301: if (i < 0) p = absi(p);
302:
303: lp = lg(primetab);
304: L = cgetg(2*lp,t_VEC); k = 1;
305: for (i=1; i < lp; i++)
306: {
307: GEN n = (GEN)primetab[i], d = mppgcd(n, p);
308: if (! is_pm1(d))
309: {
310: if (!egalii(p,d)) L[k++] = (long)d;
311: L[k++] = ldivii(n,d);
312: gunclone(n); primetab[i] = 0;
313: }
314: }
1.2 ! noro 315: primetab = (GEN) gprealloc(primetab, (lp+1)*sizeof(long));
1.1 noro 316: primetab[i] = lclone(p); setlg(primetab, lp+1);
1.2 ! noro 317: if (k > 1) { cleanprimetab(); setlg(L,k); (void)addprimes(L); }
1.1 noro 318: avma = av; return primetab;
319: }
320:
321: static GEN
322: removeprime(GEN prime)
323: {
324: long i;
325:
326: if (typ(prime) != t_INT) err(typeer,"removeprime");
327: for (i=lg(primetab) - 1; i; i--)
328: if (absi_equal((GEN) primetab[i], prime))
329: {
330: gunclone((GEN)primetab[i]); primetab[i]=0;
331: cleanprimetab(); break;
332: }
333: if (!i) err(talker,"prime %Z is not in primetable", prime);
334: return primetab;
335: }
336:
337: GEN
338: removeprimes(GEN prime)
339: {
340: long i,tx;
341:
342: if (!prime) return primetab;
343: tx = typ(prime);
344: if (is_vec_t(tx))
345: {
346: if (prime == primetab)
347: {
348: for (i=1; i < lg(prime); i++) gunclone((GEN)prime[i]);
349: setlg(prime, 1);
350: }
351: else
352: {
1.2 ! noro 353: for (i=1; i < lg(prime); i++) (void)removeprime((GEN) prime[i]);
1.1 noro 354: }
355: return primetab;
356: }
357: return removeprime(prime);
358: }
359:
360: /***********************************************************************/
361: /** **/
362: /** COMPUTING THE MATRIX OF PRIME DIVISORS AND EXPONENTS **/
363: /** **/
364: /***********************************************************************/
365:
366: /* Configure may/should define this to 1 if MPQS is not installed --GN */
367: #ifndef decomp_default_hint
368: #define decomp_default_hint 0
369: #endif
370:
371: /* Some overkill removed from this (15 spsp for an integer < 2^32 ?!).
372: Should really revert to isprime() once the new primality tester is ready
373: --GN */
1.2 ! noro 374: #if 0
1.1 noro 375: #define pseudoprime(p) millerrabin(p,3*lgefint(p))
1.2 ! noro 376: #else /* remove further overkill :-) --KB */
! 377: #define pseudoprime(p) BSW_psp(p)
! 378: #endif
1.1 noro 379:
380: /* where to stop trial dividing in factorization */
381:
382: static long
383: tridiv_bound(GEN n, long all)
384: {
385: long size = expi(n) + 1;
386: if (all > 1) /* bounded factoring */
387: return all; /* use the given limit */
388: if (all == 0)
389: return VERYBIGINT; /* smallfact() case */
390: if (size <= 32)
391: return 16384;
392: else if (size <= 512)
393: return (size-16) << 10;
394: return 1L<<19; /* Rho will generally be faster above this */
395: }
396:
397: /* function imported from ifactor1.c */
398: extern long ifac_decomp(GEN n, long hint);
399: extern long ifac_decomp_break(GEN n, long (*ifac_break)(GEN,GEN,GEN,GEN),
400: GEN state, long hint);
401: static GEN
402: aux_end(GEN n, long nb)
403: {
404: GEN p1,p2, z = (GEN)avma;
405: long i;
406:
407: if (n) gunclone(n);
408: p1=cgetg(nb+1,t_COL);
409: p2=cgetg(nb+1,t_COL);
410: for (i=nb; i; i--)
411: {
412: p2[i] = (long)z; z += lg(z);
413: p1[i] = (long)z; z += lg(z);
414: }
415: z[1] = (long)p1;
416: z[2] = (long)p2;
417: if (nb) (void)sort_factor_gen(z,cmpii);
418: return z;
419: }
420:
421: GEN
422: auxdecomp1(GEN n, long (*ifac_break)(GEN n, GEN pairs, GEN here, GEN state),
423: GEN state, long all, long hint)
424: {
1.2 ! noro 425: gpmem_t av;
! 426: long pp[] = { evaltyp(t_INT)|_evallg(4), 0,0,0 };
! 427: long nb = 0,i,k,lp,p,lim1;
1.1 noro 428: byteptr d=diffptr+1;
429:
430: if (typ(n) != t_INT) err(arither1);
431: i=signe(n); if (!i) err(arither2);
1.2 ! noro 432: (void)cgetg(3,t_MAT);
! 433: if (i<0) { (void)stoi(-1); (void)stoi(1); nb++; }
1.1 noro 434: if (is_pm1(n)) return aux_end(NULL,nb);
435:
436: n = gclone(n); setsigne(n,1);
437: i = vali(n);
438: if (i)
439: {
1.2 ! noro 440: (void)stoi(2); (void)stoi(i); nb++;
1.1 noro 441: av=avma; affii(shifti(n,-i), n); avma=av;
442: }
443: if (is_pm1(n)) return aux_end(n,nb);
444: lim1 = tridiv_bound(n, all);
445:
446: /* trial division */
1.2 ! noro 447: p = 2;
! 448: while (*d && p <= lim1)
1.1 noro 449: {
1.2 ! noro 450: NEXT_PRIME_VIADIFF(p,d);
! 451: if (mpdivisis(n,p,n))
1.1 noro 452: {
1.2 ! noro 453: nb++; k=1; while (mpdivisis(n,p,n)) k++;
! 454: (void)utoi(p); (void)stoi(k);
1.1 noro 455: if (is_pm1(n)) return aux_end(n,nb);
456: }
457: }
458:
459: /* pp = square of biggest p tried so far */
1.2 ! noro 460: av=avma; affii(muluu(p,p),pp); avma=av;
1.1 noro 461: if (cmpii(pp,n) > 0)
462: {
463: nb++;
1.2 ! noro 464: (void)icopy(n); (void)stoi(1); return aux_end(n,nb);
1.1 noro 465: }
466:
467: /* trial divide by the "special primes" (usually huge composites...) */
468: lp = lg(primetab); k=0;
469: for (i=1; i<lp; i++)
470: if (mpdivis(n,(GEN) primetab[i],n))
471: {
472: nb++; k=1; while (mpdivis(n,(GEN) primetab[i],n)) k++;
1.2 ! noro 473: (void)icopy((GEN) primetab[i]); (void)stoi(k);
1.1 noro 474: if (is_pm1(n)) return aux_end(n,nb);
475: }
476:
477: /* test primality (unless all != 1 (i.e smallfact))*/
478: if ((k && cmpii(pp,n) > 0) || (all==1 && pseudoprime(n)))
479: {
480: nb++;
1.2 ! noro 481: (void)icopy(n); (void)stoi(1); return aux_end(n,nb);
1.1 noro 482: }
483:
484: /* now we have a large composite. Use hint as is if all==1 */
485: if (all!=1) hint = 15; /* turn off everything except pure powers */
486: if (ifac_break && (*ifac_break)(n,NULL,NULL,state))
487: /*Initialize ifac_break*/
488: {
489: if (DEBUGLEVEL >= 3)
490: fprintferr("IFAC: (Partial fact.) Initial stop requested.\n");
491: }
492: else
493: nb += ifac_decomp_break(n, ifac_break, state, hint);
494:
495: return aux_end(n, nb);
496: }
497:
498: /* state[1]: current unfactored part.
499: * state[2]: limit. */
500: static long
501: ifac_break_limit(GEN n, GEN pairs/*unused*/, GEN here, GEN state)
502: {
1.2 ! noro 503: gpmem_t ltop = avma;
1.1 noro 504: int res;
505: if (!here) /* initial call */
506: /* Small prime have been removed since start, n is the new unfactored part.
507: * Result is affect()ed to state[1] to preserve stack. */
508: affii(n, (GEN)state[1]);
509: else
510: {
511: GEN q = powgi((GEN)here[0],(GEN)here[1]); /* primary factor found.*/
512: if (DEBUGLEVEL>2) fprintferr("IFAC: Stop: Primary factor: %Z\n",q);
513: /* divide unfactored part by q and assign the result to state[1] */
514: diviiz((GEN)state[1],q, (GEN)state[1]);
515: }
516: if (DEBUGLEVEL>=3) fprintferr("IFAC: Stop: remaining %Z\n",state[1]);
517: /* check the stopping criterion, then restore stack */
518: res = cmpii((GEN)state[1],(GEN)state[2]) <= 0;
519: avma = ltop; return res;
520: }
521:
522: static GEN
523: auxdecomp0(GEN n, long all, long hint)
524: {
525: return auxdecomp1(n, NULL, gzero, all, hint);
526: }
527:
528: GEN
529: auxdecomp(GEN n, long all)
530: {
531: return auxdecomp0(n,all,decomp_default_hint);
532: }
533:
534: /* see before ifac_crack() in ifactor1.c for current semantics of `hint'
535: (factorint's `flag') */
536: GEN
537: factorint(GEN n, long flag)
538: {
539: return auxdecomp0(n,1,flag);
540: }
541:
542: GEN
543: decomp(GEN n)
544: {
545: return auxdecomp0(n,1,decomp_default_hint);
546: }
547:
548: /* Factor until the unfactored part is smaller than limit. */
549: GEN
550: decomp_limit(GEN n, GEN limit)
551: {
552: GEN state = cgetg(3,t_VEC);
553: /* icopy is mainly done to allocate memory for affect().
554: * Currently state[1] value is discarded in initial call to ifac_break_limit */
555: state[1] = licopy(n);
556: state[2] = lcopy(limit);
557: return auxdecomp1(n, &ifac_break_limit, state, 1, decomp_default_hint);
558: }
559:
560: GEN
561: smallfact(GEN n)
562: {
563: return boundfact(n,0);
564: }
565:
566: GEN
567: gboundfact(GEN n, long lim)
568: {
569: return garith_proto2gs(boundfact,n,lim);
570: }
571:
572: GEN
573: boundfact(GEN n, long lim)
574: {
575: GEN p1,p2,p3,p4,p5,y;
1.2 ! noro 576: gpmem_t av = avma,tetpil;
1.1 noro 577:
578: if (lim<=1) lim=0;
579: switch(typ(n))
580: {
581: case t_INT:
582: return auxdecomp(n,lim);
583: case t_FRACN:
1.2 ! noro 584: n=gred(n);
! 585: if (typ(n) == t_INT)
! 586: return gerepileupto(av, boundfact(n,lim));
! 587: /* fall through */
1.1 noro 588: case t_FRAC:
589: p1=auxdecomp((GEN)n[1],lim);
590: p2=auxdecomp((GEN)n[2],lim);
591: p4=concatsp((GEN)p1[1],(GEN)p2[1]);
592: p5=concatsp((GEN)p1[2],gneg((GEN)p2[2]));
593: p3=indexsort(p4);
594:
595: tetpil=avma; y=cgetg(3,t_MAT);
596: y[1]=(long)extract(p4,p3);
597: y[2]=(long)extract(p5,p3);
598: return gerepile(av,tetpil,y);
599: }
600: err(arither1);
601: return NULL; /* not reached */
602: }
1.2 ! noro 603: /***********************************************************************/
! 604: /** **/
! 605: /** SIMPLE FACTORISATIONS **/
! 606: /** **/
! 607: /***********************************************************************/
! 608:
! 609: /*Factorize n and output [fp,fe] where
! 610: * fp and fe are vecsmall and n=prod{fp[i]^fe[i]}
! 611: */
! 612:
! 613: GEN
! 614: decomp_small(long n)
! 615: {
! 616: gpmem_t ltop=avma;
! 617: GEN F = factor(stoi(n));
! 618: long i, l=lg(F[1]);
! 619: GEN f=cgetg(3,t_VEC);
! 620: GEN fp=cgetg(l,t_VECSMALL);
! 621: GEN fe=cgetg(l,t_VECSMALL);
! 622: f[1] = (long) fp;
! 623: f[2] = (long) fe;
! 624: for(i = 1; i < l; i++)
! 625: {
! 626: fp[i]=itos(gcoeff(F,i,1));
! 627: fe[i]=itos(gcoeff(F,i,2));
! 628: }
! 629: return gerepileupto(ltop,f);
! 630: }
! 631:
! 632: /*Return the primary factors of a small integer as a vecsmall*/
! 633: GEN
! 634: decomp_primary_small(long n)
! 635: {
! 636: gpmem_t ltop=avma;
! 637: GEN F = factor(stoi(n));
! 638: GEN fc = cgetg(lg(F[1]), t_VECSMALL);
! 639: gpmem_t av=avma;
! 640: long i;
! 641: for (i = 1; i < lg(fc); i++)
! 642: fc[i] = itos(powgi(gmael(F,1,i), gmael(F,2,i)));
! 643: avma=av;
! 644: return gerepileupto(ltop,fc);
! 645: }
! 646:
1.1 noro 647:
648: /***********************************************************************/
649: /** **/
650: /** BASIC ARITHMETIC FUNCTIONS **/
651: /** **/
652: /***********************************************************************/
653:
654: /* functions imported from ifactor1.c */
655: long
656: ifac_moebius(GEN n, long hint);
657:
658: long
659: ifac_issquarefree(GEN n, long hint);
660:
661: long
662: ifac_omega(GEN n, long hint);
663:
664: long
665: ifac_bigomega(GEN n, long hint);
666:
667: GEN
668: ifac_totient(GEN n, long hint);
669:
670: GEN
671: ifac_numdiv(GEN n, long hint);
672:
673: GEN
674: ifac_sumdiv(GEN n, long hint);
675:
676: GEN
677: ifac_sumdivk(GEN n, long k, long hint);
678:
679: GEN
680: gmu(GEN n)
681: {
682: return arith_proto(mu,n,1);
683: }
684:
685: long
686: mu(GEN n)
687: {
688: byteptr d = diffptr+1; /* point at 3 - 2 */
1.2 ! noro 689: gpmem_t av = avma;
! 690: ulong p;
! 691: long s, v, lim1;
1.1 noro 692:
693: if (typ(n) != t_INT) err(arither1);
694: if (!signe(n)) err(arither2);
695: if (is_pm1(n)) return 1;
696: v = vali(n);
697: if (v>1) return 0;
698: s = v ? -1 : 1;
699: n=absi(shifti(n,-v)); p = 2;
700: if (is_pm1(n)) return s;
701: lim1 = tridiv_bound(n,1);
702:
703: while (*d && p < lim1)
704: {
1.2 ! noro 705: NEXT_PRIME_VIADIFF(p,d);
1.1 noro 706: if (mpdivisis(n,p,n))
707: {
708: if (smodis(n,p) == 0) { avma=av; return 0; }
709: s = -s; if (is_pm1(n)) { avma=av; return s; }
710: }
711: }
712: /* we normally get here with p==nextprime(PRE_TUNE), which will already
713: have been tested against n, so p^2 >= n (instead of p^2 > n) is
714: enough to guarantee n is prime */
715: if (cmpii(sqru(p),n) >= 0 || pseudoprime(n)) { avma=av; return -s; }
716: /* large composite without small factors */
717: v = ifac_moebius(n, decomp_default_hint);
718: avma=av;
719: return (s<0 ? -v : v); /* correct also if v==0 */
720: }
721:
722: GEN
723: gissquarefree(GEN x)
724: {
725: return arith_proto(issquarefree,x,0);
726: }
727:
728: long
729: issquarefree(GEN x)
730: {
1.2 ! noro 731: ulong p;
! 732: gpmem_t av = avma;
! 733: long tx, lim1;
1.1 noro 734: GEN d;
735:
736: if (gcmp0(x)) return 0;
737: tx = typ(x);
738: if (tx == t_INT)
739: {
740: long v;
741: byteptr d=diffptr+1;
742: if (is_pm1(x)) return 1;
743: if((v = vali(x)) > 1) return 0;
744: x = absi(shifti(x,-v));
745: if (is_pm1(x)) return 1;
746: lim1 = tridiv_bound(x,1);
747:
748: p = 2;
749: while (*d && p < lim1)
750: {
1.2 ! noro 751: NEXT_PRIME_VIADIFF(p,d);
1.1 noro 752: if (mpdivisis(x,p,x))
753: {
754: if (smodis(x,p) == 0) { avma = av; return 0; }
755: if (is_pm1(x)) { avma = av; return 1; }
756: }
757: }
758: if (cmpii(sqru(p),x) >= 0 || pseudoprime(x)) { avma = av; return 1; }
759: v = ifac_issquarefree(x, decomp_default_hint);
760: avma = av; return v;
761: }
762: if (tx != t_POL) err(typeer,"issquarefree");
763: d = ggcd(x, derivpol(x));
764: avma = av; return (lgef(d) == 3);
765: }
766:
767: GEN
768: gomega(GEN n)
769: {
770: return arith_proto(omega,n,1);
771: }
772:
773: long
774: omega(GEN n)
775: {
776: byteptr d=diffptr+1;
1.2 ! noro 777: gpmem_t av = avma;
! 778: long p,nb,v, lim1;
1.1 noro 779:
780: if (typ(n) != t_INT) err(arither1);
781: if (!signe(n)) err(arither2);
782: if (is_pm1(n)) return 0;
783: v=vali(n);
784: nb = v ? 1 : 0;
785: n = absi(shifti(n,-v)); p = 2;
786: if (is_pm1(n)) return nb;
787: lim1 = tridiv_bound(n,1);
788:
789: while (*d && p < lim1)
790: {
1.2 ! noro 791: NEXT_PRIME_VIADIFF(p,d);
1.1 noro 792: if (mpdivisis(n,p,n))
793: {
794: nb++; while (mpdivisis(n,p,n)); /* empty */
795: if (is_pm1(n)) { avma = av; return nb; }
796: }
797: }
798: if (cmpii(sqru(p),n) >= 0 || pseudoprime(n)) { avma = av; return nb+1; }
799: /* large composite without small factors */
800: nb += ifac_omega(n, decomp_default_hint);
801: avma=av; return nb;
802: }
803:
804: GEN
805: gbigomega(GEN n)
806: {
807: return arith_proto(bigomega,n,1);
808: }
809:
810: long
811: bigomega(GEN n)
812: {
813: byteptr d=diffptr+1;
1.2 ! noro 814: ulong p;
! 815: gpmem_t av = avma;
! 816: long nb,v, lim1;
1.1 noro 817:
818: if (typ(n) != t_INT) err(arither1);
819: if (!signe(n)) err(arither2);
820: if (is_pm1(n)) return 0;
821: nb=v=vali(n);
822: n=absi(shifti(n,-v)); p = 2;
823: if (is_pm1(n)) { avma = av; return nb; }
824: lim1 = tridiv_bound(n,1);
825:
826: while (*d && p < lim1)
827: {
1.2 ! noro 828: NEXT_PRIME_VIADIFF(p,d);
1.1 noro 829: if (mpdivisis(n,p,n))
830: {
831: do nb++; while (mpdivisis(n,p,n));
832: if (is_pm1(n)) { avma = av; return nb; }
833: }
834: }
835: if (cmpii(sqru(p),n) >= 0 || pseudoprime(n)) { avma = av; return nb+1; }
836: nb += ifac_bigomega(n, decomp_default_hint);
837: avma=av; return nb;
838: }
839:
840: GEN
841: gphi(GEN n)
842: {
843: return garith_proto(phi,n,1);
844: }
845:
846: GEN
847: phi(GEN n)
848: {
849: byteptr d = diffptr+1;
850: GEN m;
1.2 ! noro 851: ulong p;
! 852: gpmem_t av = avma;
! 853: long v, lim1;
1.1 noro 854:
855: if (typ(n) != t_INT) err(arither1);
856: if (!signe(n)) err(arither2);
857: if (is_pm1(n)) return gun;
858: v = vali(n);
859: n = absi(shifti(n,-v)); p = 2;
860: m = (v > 1 ? shifti(gun,v-1) : stoi(1));
861: if (is_pm1(n)) { return gerepileupto(av,m); }
862: lim1 = tridiv_bound(n,1);
863:
864: while (*d && p < lim1)
865: {
1.2 ! noro 866: NEXT_PRIME_VIADIFF(p,d);
1.1 noro 867: if (mpdivisis(n,p,n))
868: {
869: m = mulis(m, p-1);
870: while (mpdivisis(n,p,n)) m = mulis(m,p);
871: if (is_pm1(n)) { return gerepileupto(av,m); }
872: }
873: }
874: if (cmpii(sqru(p),n) >= 0 || pseudoprime(n))
875: {
876: m = mulii(m,addsi(-1,n));
877: return gerepileupto(av,m);
878: }
879: m = mulii(m, ifac_totient(n, decomp_default_hint));
880: return gerepileupto(av,m);
881: }
882:
883: GEN
884: gnumbdiv(GEN n)
885: {
886: return garith_proto(numbdiv,n,1);
887: }
888:
889: GEN
890: numbdiv(GEN n)
891: {
892: byteptr d=diffptr+1;
893: GEN m;
1.2 ! noro 894: long l, v, lim1;
! 895: ulong p;
! 896: gpmem_t av = avma;
1.1 noro 897:
898: if (typ(n) != t_INT) err(arither1);
899: if (!signe(n)) err(arither2);
900: if (is_pm1(n)) return gun;
901: v = vali(n);
902: n = absi(shifti(n,-v)); p = 2;
903: m = stoi(v+1);
904: if (is_pm1(n)) return gerepileupto(av,m);
905: lim1 = tridiv_bound(n,1);
906:
907: while (*d && p < lim1)
908: {
1.2 ! noro 909: NEXT_PRIME_VIADIFF(p,d);
1.1 noro 910: l=1; while (mpdivisis(n,p,n)) l++;
911: m = mulsi(l,m); if (is_pm1(n)) { return gerepileupto(av,m); }
912: }
913: if(cmpii(sqru(p),n) >= 0 || pseudoprime(n))
914: {
915: m = shifti(m,1);
916: return gerepileupto(av,m);
917: }
918: m = mulii(m, ifac_numdiv(n, decomp_default_hint));
919: return gerepileupto(av,m);
920: }
921:
922: GEN
923: gsumdiv(GEN n)
924: {
925: return garith_proto(sumdiv,n,1);
926: }
927:
928: GEN
929: sumdiv(GEN n)
930: {
931: byteptr d=diffptr+1;
932: GEN m,m1;
1.2 ! noro 933: ulong p;
! 934: gpmem_t av=avma;
! 935: long v, lim1;
1.1 noro 936:
937: if (typ(n) != t_INT) err(arither1);
938: if (!signe(n)) err(arither2);
939: if (is_pm1(n)) return gun;
940: v = vali(n);
941: n = absi(shifti(n,-v)); p = 2;
942: m = (v ? addsi(-1,shifti(gun,v+1)) : stoi(1));
943: if (is_pm1(n)) { return gerepileupto(av,m); }
944: lim1 = tridiv_bound(n,1);
945:
946: while (*d && p < lim1)
947: {
1.2 ! noro 948: NEXT_PRIME_VIADIFF(p,d);
1.1 noro 949: if (mpdivisis(n,p,n))
950: {
951: m1 = utoi(p+1);
952: while (mpdivisis(n,p,n)) m1 = addsi(1, mului(p,m1));
953: m = mulii(m1,m); if (is_pm1(n)) { return gerepileupto(av,m); }
954: }
955: }
956: if(cmpii(sqru(p),n) >= 0 || pseudoprime(n))
957: {
958: m = mulii(m,addsi(1,n));
959: return gerepileupto(av,m);
960: }
961: m = mulii(m, ifac_sumdiv(n, decomp_default_hint));
962: return gerepileupto(av,m);
963: }
964:
965: GEN
966: gsumdivk(GEN n, long k)
967: {
968: return garith_proto2gs(sumdivk,n,k);
969: }
970:
971: GEN
972: sumdivk(GEN n, long k)
973: {
974: byteptr d=diffptr+1;
975: GEN n1,m,m1,pk;
1.2 ! noro 976: ulong p;
! 977: gpmem_t av = avma;
! 978: long k1,v, lim1;
1.1 noro 979:
980: if (!k) return numbdiv(n);
981: if (k==1) return sumdiv(n);
982: if (typ(n) != t_INT) err(arither1);
983: if (!signe(n)) err(arither2);
984: if (is_pm1(n)) return gun;
985: k1 = k; n1 = n;
986: if (k==-1) { m=sumdiv(n); goto fin; }
987: if (k<0) k = -k;
988: v=vali(n);
989: n=absi(shifti(n,-v));
990: p = 2; m = stoi(1);
991: while (v--) m = addsi(1,shifti(m,k));
992: if (is_pm1(n)) goto fin;
993: lim1 = tridiv_bound(n,1);
994:
995: while (*d && p < lim1)
996: {
1.2 ! noro 997: NEXT_PRIME_VIADIFF(p,d);
1.1 noro 998: if (mpdivisis(n,p,n))
999: {
1000: pk = gpowgs(utoi(p),k); m1 = addsi(1,pk);
1001: while (mpdivisis(n,p,n)) m1 = addsi(1, mulii(pk,m1));
1002: m = mulii(m1,m); if (is_pm1(n)) goto fin;
1003: }
1004: }
1005: if(cmpii(sqru(p),n) >= 0 || pseudoprime(n))
1006: {
1007: pk = gpuigs(n,k);
1008: m = mulii(m,addsi(1,pk));
1009: goto fin;
1010: }
1011: m = mulii(m, ifac_sumdivk(n, k, decomp_default_hint));
1012: fin:
1013: if (k1 < 0) m = gdiv(m, gpowgs(n1,k));
1014: return gerepileupto(av,m);
1015: }
1016:
1017: /***********************************************************************/
1018: /** **/
1019: /** MISCELLANEOUS ARITHMETIC FUNCTIONS **/
1020: /** (all of these ultimately depend on auxdecomp()) **/
1021: /** **/
1022: /***********************************************************************/
1023:
1024: GEN
1025: divisors(GEN n)
1026: {
1.2 ! noro 1027: gpmem_t tetpil,av=avma;
! 1028: long i,j,l;
1.1 noro 1029: GEN *d,*t,*t1,*t2,*t3, nbdiv,e;
1030:
1031: if (typ(n) != t_MAT || lg(n) != 3) n = auxdecomp(n,1);
1032:
1033: e = (GEN) n[2], n = (GEN) n[1]; l = lg(n);
1034: if (l>1 && signe(n[1]) < 0) { e++; n++; l--; } /* skip -1 */
1035: nbdiv = gun;
1036: for (i=1; i<l; i++)
1037: {
1038: e[i] = itos((GEN)e[i]);
1039: nbdiv = mulis(nbdiv,1+e[i]);
1040: }
1041: if (is_bigint(nbdiv) || (itos(nbdiv) & ~LGBITS))
1042: err(talker, "too many divisors (more than %ld)", LGBITS - 1);
1043: d = t = (GEN*) cgetg(itos(nbdiv)+1,t_VEC);
1044: *++d = gun;
1045: for (i=1; i<l; i++)
1046: for (t1=t,j=e[i]; j; j--,t1=t2)
1047: for (t2=d,t3=t1; t3<t2; )
1048: *++d = mulii(*++t3, (GEN)n[i]);
1049: tetpil=avma; return gerepile(av,tetpil,sort((GEN)t));
1050: }
1051:
1.2 ! noro 1052: static GEN
! 1053: _core(GEN n, int all)
1.1 noro 1054: {
1.2 ! noro 1055: gpmem_t av = avma;
! 1056: long i;
! 1057: GEN fa,p1,p2,c = gun;
1.1 noro 1058:
1.2 ! noro 1059: fa = auxdecomp(n,all);
! 1060: p1 = (GEN)fa[1];
! 1061: p2 = (GEN)fa[2];
1.1 noro 1062: for (i=1; i<lg(p1); i++)
1.2 ! noro 1063: if (mod2((GEN)p2[i])) c = mulii(c,(GEN)p1[i]);
! 1064: return gerepileuptoint(av, c);
1.1 noro 1065: }
1066:
1.2 ! noro 1067: static GEN
! 1068: _core2(GEN n, int all)
1.1 noro 1069: {
1.2 ! noro 1070: gpmem_t av = avma;
! 1071: long i;
! 1072: GEN fa,p1,p2,e,c=gun,f=gun,y;
1.1 noro 1073:
1.2 ! noro 1074: fa = auxdecomp(n,all);
! 1075: p1 = (GEN)fa[1];
! 1076: p2 = (GEN)fa[2];
1.1 noro 1077: for (i=1; i<lg(p1); i++)
1078: {
1.2 ! noro 1079: e = (GEN)p2[i];
! 1080: if (mod2(e)) c = mulii(c, (GEN)p1[i]);
! 1081: if (!gcmp1(e)) f = mulii(f, powgi((GEN)p1[i], shifti(e,-1)));
1.1 noro 1082: }
1.2 ! noro 1083: y = cgetg(3,t_VEC);
! 1084: y[1] = (long)c;
! 1085: y[2] = (long)f; return gerepilecopy(av, y);
1.1 noro 1086: }
1087:
1.2 ! noro 1088: GEN core(GEN n) { return _core(n,1); }
! 1089: GEN corepartial(GEN n) { return _core(n,0); }
! 1090: GEN core2(GEN n) { return _core2(n,1); }
! 1091: GEN core2partial(GEN n){ return _core2(n,0); }
! 1092:
1.1 noro 1093: GEN
1.2 ! noro 1094: core0(GEN n,long flag) { return flag? core2(n): core(n); }
! 1095:
! 1096: static long
! 1097: _mod4(GEN c) { long r = mod4(c); if (signe(c) < 0) r = 4-r; return r; }
1.1 noro 1098:
1099: GEN
1100: coredisc(GEN n)
1101: {
1.2 ! noro 1102: gpmem_t av = avma;
! 1103: GEN c = core(n);
! 1104: long r = _mod4(c);
! 1105: if (r==1 || r==4) return c;
! 1106: return gerepileuptoint(av, shifti(c,2));
1.1 noro 1107: }
1108:
1109: GEN
1110: coredisc2(GEN n)
1111: {
1.2 ! noro 1112: gpmem_t av = avma;
! 1113: GEN y = core2(n);
! 1114: GEN c = (GEN)y[1], f = (GEN)y[2];
! 1115: long r = _mod4(c);
! 1116: if (r==1 || r==4) return y;
! 1117: y = cgetg(3,t_VEC);
! 1118: y[1] = lshifti(c,2);
! 1119: y[2] = lmul2n(f,-1); return gerepileupto(av, y);
1.1 noro 1120: }
1121:
1122: GEN
1.2 ! noro 1123: coredisc0(GEN n,long flag) { return flag? coredisc2(n): coredisc(n); }
1.1 noro 1124:
1125: /***********************************************************************/
1126: /** **/
1127: /** BINARY QUADRATIC FORMS **/
1128: /** **/
1129: /***********************************************************************/
1130:
1131: GEN
1132: qf_disc(GEN x, GEN y, GEN z)
1133: {
1134: if (!y) { y=(GEN)x[2]; z=(GEN)x[3]; x=(GEN)x[1]; }
1135: return subii(sqri(y), shifti(mulii(x,z),2));
1136: }
1137:
1138: static GEN
1139: qf_create(GEN x, GEN y, GEN z, long s)
1140: {
1141: GEN t;
1142: if (typ(x)!=t_INT || typ(y)!=t_INT || typ(z)!=t_INT) err(typeer,"Qfb");
1143: if (!s)
1144: {
1.2 ! noro 1145: gpmem_t av=avma; s = signe(qf_disc(x,y,z)); avma=av;
1.1 noro 1146: if (!s) err(talker,"zero discriminant in Qfb");
1147: }
1148: t = (s>0)? cgetg(5,t_QFR): cgetg(4,t_QFI);
1149: t[1]=(long)icopy(x); t[2]=(long)icopy(y); t[3]=(long)icopy(z);
1150: return t;
1151: }
1152:
1153: GEN
1154: qfi(GEN x, GEN y, GEN z)
1155: {
1156: return qf_create(x,y,z,-1);
1157: }
1158:
1159: GEN
1160: qfr(GEN x, GEN y, GEN z, GEN d)
1161: {
1162: GEN t = qf_create(x,y,z,1);
1163: if (typ(d) != t_REAL)
1164: err(talker,"Shanks distance should be a t_REAL (in qfr)");
1165: t[4]=lrcopy(d); return t;
1166: }
1167:
1168: GEN
1169: Qfb0(GEN x, GEN y, GEN z, GEN d, long prec)
1170: {
1171: GEN t = qf_create(x,y,z,0);
1172: if (lg(t)==4) return t;
1173: if (!d) d = gzero;
1174: if (typ(d) == t_REAL)
1175: t[4] = lrcopy(d);
1176: else
1177: { t[4]=lgetr(prec); gaffect(d,(GEN)t[4]); }
1178: return t;
1179: }
1180:
1181: /* composition */
1182: static void
1183: sq_gen(GEN z, GEN x)
1184: {
1185: GEN d1,x2,y2,v1,v2,c3,m,p1,r;
1186:
1187: d1 = bezout((GEN)x[2],(GEN)x[1],&x2,&y2);
1188: if (gcmp1(d1)) v1 = v2 = (GEN)x[1];
1189: else
1190: {
1191: v1 = divii((GEN)x[1],d1);
1192: v2 = mulii(v1,mppgcd(d1,(GEN)x[3]));
1193: }
1194: m = mulii((GEN)x[3],x2); setsigne(m,-signe(m));
1195: r = modii(m,v2); p1 = mulii(v1,r);
1196: c3 = addii(mulii((GEN)x[3],d1), mulii(r,addii((GEN)x[2],p1)));
1197: z[1] = lmulii(v1,v2);
1198: z[2] = laddii((GEN)x[2], shifti(p1,1));
1199: z[3] = ldivii(c3,v2);
1200: }
1201:
1202: void
1203: comp_gen(GEN z,GEN x,GEN y)
1204: {
1205: GEN s,n,d,d1,x1,x2,y1,y2,v1,v2,c3,m,p1,r;
1206:
1207: if (x == y) { sq_gen(z,x); return; }
1208: s = shifti(addii((GEN)x[2],(GEN)y[2]),-1);
1209: n = subii((GEN)y[2],s);
1210: d = bezout((GEN)y[1],(GEN)x[1],&y1,&x1);
1211: d1 = bezout(s,d,&x2,&y2);
1212: if (gcmp1(d1))
1213: {
1214: v1 = (GEN)x[1];
1215: v2 = (GEN)y[1];
1216: }
1217: else
1218: {
1219: v1 = divii((GEN)x[1],d1);
1220: v2 = divii((GEN)y[1],d1);
1221: v1 = mulii(v1, mppgcd(d1,mppgcd((GEN)x[3],mppgcd((GEN)y[3],n))));
1222: }
1223: m = addii(mulii(mulii(y1,y2),n), mulii((GEN)y[3],x2));
1224: setsigne(m,-signe(m));
1225: r = modii(m,v1); p1 = mulii(v2,r);
1226: c3 = addii(mulii((GEN)y[3],d1), mulii(r,addii((GEN)y[2],p1)));
1227: z[1] = lmulii(v1,v2);
1228: z[2] = laddii((GEN)y[2], shifti(p1,1));
1229: z[3] = ldivii(c3,v1);
1230: }
1231:
1232: static GEN
1233: compimag0(GEN x, GEN y, int raw)
1234: {
1.2 ! noro 1235: gpmem_t av = avma;
! 1236: long tx = typ(x);
1.1 noro 1237: GEN z;
1238:
1239: if (typ(y) != tx || tx!=t_QFI) err(typeer,"composition");
1240: if (cmpii((GEN)x[1],(GEN)y[1]) > 0) { z=x; x=y; y=z; }
1241: z=cgetg(4,t_QFI); comp_gen(z,x,y);
1242: if (raw) return gerepilecopy(av,z);
1243: return gerepileupto(av, redimag(z));
1244: }
1245:
1246: static GEN
1247: compreal0(GEN x, GEN y, int raw)
1248: {
1.2 ! noro 1249: gpmem_t av = avma;
! 1250: long tx = typ(x);
1.1 noro 1251: GEN z;
1252:
1253: if (typ(y) != tx || tx!=t_QFR) err(typeer,"composition");
1254: z=cgetg(5,t_QFR); comp_gen(z,x,y);
1255: z[4]=laddrr((GEN)x[4],(GEN)y[4]);
1256: if (raw) return gerepilecopy(av,z);
1257: return gerepileupto(av,redreal(z));
1258: }
1259:
1260: GEN
1261: compreal(GEN x, GEN y) { return compreal0(x,y,0); }
1262:
1263: GEN
1264: comprealraw(GEN x, GEN y) { return compreal0(x,y,1); }
1265:
1266: GEN
1267: compimag(GEN x, GEN y) { return compimag0(x,y,0); }
1268:
1269: GEN
1270: compimagraw(GEN x, GEN y) { return compimag0(x,y,1); }
1271:
1272: GEN
1273: compraw(GEN x, GEN y)
1274: {
1275: return (typ(x)==t_QFI)? compimagraw(x,y): comprealraw(x,y);
1276: }
1277:
1278: GEN
1279: sqcompimag0(GEN x, long raw)
1280: {
1.2 ! noro 1281: gpmem_t av = avma;
1.1 noro 1282: GEN z = cgetg(4,t_QFI);
1283:
1284: if (typ(x)!=t_QFI) err(typeer,"composition");
1285: sq_gen(z,x);
1286: if (raw) return gerepilecopy(av,z);
1287: return gerepileupto(av,redimag(z));
1288: }
1289:
1290: static GEN
1291: sqcompreal0(GEN x, long raw)
1292: {
1.2 ! noro 1293: gpmem_t av = avma;
1.1 noro 1294: GEN z = cgetg(5,t_QFR);
1295:
1296: if (typ(x)!=t_QFR) err(typeer,"composition");
1297: sq_gen(z,x); z[4]=lshiftr((GEN)x[4],1);
1298: if (raw) return gerepilecopy(av,z);
1299: return gerepileupto(av,redreal(z));
1300: }
1301:
1302: GEN
1303: sqcompreal(GEN x) { return sqcompreal0(x,0); }
1304:
1305: GEN
1306: sqcomprealraw(GEN x) { return sqcompreal0(x,1); }
1307:
1308: GEN
1309: sqcompimag(GEN x) { return sqcompimag0(x,0); }
1310:
1311: GEN
1312: sqcompimagraw(GEN x) { return sqcompimag0(x,1); }
1313:
1314: static GEN
1315: real_unit_form_by_disc(GEN D, long prec)
1316: {
1317: GEN y = cgetg(5,t_QFR), isqrtD;
1.2 ! noro 1318: gpmem_t av = avma;
1.1 noro 1319:
1320: if (typ(D) != t_INT || signe(D) <= 0) err(typeer,"real_unit_form_by_disc");
1321: switch(mod4(D))
1322: {
1323: case 2:
1324: case 3: err(funder2,"real_unit_form_by_disc");
1325: }
1326: y[1]=un; isqrtD = racine(D);
1327: /* we know that D and isqrtD are non-zero */
1328: if (mod2(D) != mod2(isqrtD))
1329: isqrtD = gerepileuptoint(av, addsi(-1,isqrtD));
1330: y[2] = (long)isqrtD; av = avma;
1.2 ! noro 1331: y[3] = lpileuptoint(av, shifti(subii(sqri(isqrtD),D),-2));
1.1 noro 1332: y[4] = (long)realzero(prec); return y;
1333: }
1334:
1335: GEN
1336: real_unit_form(GEN x)
1337: {
1.2 ! noro 1338: gpmem_t av = avma;
! 1339: long prec;
1.1 noro 1340: GEN D;
1341: if (typ(x) != t_QFR) err(typeer,"real_unit_form");
1342: prec = precision((GEN)x[4]);
1343: if (!prec) err(talker,"not a t_REAL in 4th component of a t_QFR");
1344: D = qf_disc(x,NULL,NULL);
1345: return gerepileupto(av, real_unit_form_by_disc(D,prec));
1346: }
1347:
1348: static GEN
1349: imag_unit_form_by_disc(GEN D)
1350: {
1351: GEN y = cgetg(4,t_QFI);
1352: long isodd;
1353:
1354: if (typ(D) != t_INT || signe(D) >= 0) err(typeer,"real_unit_form_by_disc");
1355: switch(4 - mod4(D))
1356: {
1357: case 2:
1358: case 3: err(funder2,"imag_unit_form_by_disc");
1359: }
1360: y[1] = un; isodd = mpodd(D);
1361: y[2] = isodd? un: zero;
1362: /* y[3] = (1-D) / 4 or -D / 4, whichever is an integer */
1363: y[3] = lshifti(D,-2); setsigne(y[3],1);
1364: if (isodd)
1365: {
1.2 ! noro 1366: gpmem_t av = avma;
! 1367: y[3] = lpileuptoint(av, addis((GEN)y[3],1));
1.1 noro 1368: }
1369: return y;
1370: }
1371:
1372: GEN
1373: imag_unit_form(GEN x)
1374: {
1375: GEN p1,p2, y = cgetg(4,t_QFI);
1.2 ! noro 1376: gpmem_t av;
1.1 noro 1377: if (typ(x) != t_QFI) err(typeer,"imag_unit_form");
1378: y[1] = un;
1379: y[2] = mpodd((GEN)x[2])? un: zero;
1380: av = avma; p1 = mulii((GEN)x[1],(GEN)x[3]);
1381: p2 = shifti(sqri((GEN)x[2]),-2);
1.2 ! noro 1382: y[3] = lpileuptoint(av, subii(p1,p2));
1.1 noro 1383: return y;
1384: }
1385:
1386: GEN
1387: powrealraw(GEN x, long n)
1388: {
1.2 ! noro 1389: gpmem_t av = avma;
! 1390: long m;
1.1 noro 1391: GEN y;
1392:
1393: if (typ(x) != t_QFR)
1394: err(talker,"not a real quadratic form in powrealraw");
1395: if (!n) return real_unit_form(x);
1396: if (n== 1) return gcopy(x);
1397: if (n==-1) return ginv(x);
1398:
1399: y = NULL; m=labs(n);
1400: for (; m>1; m>>=1)
1401: {
1402: if (m&1) y = y? comprealraw(y,x): x;
1403: x=sqcomprealraw(x);
1404: }
1405: y = y? comprealraw(y,x): x;
1406: if (n<0) y = ginv(y);
1407: return gerepileupto(av,y);
1408: }
1409:
1410: GEN
1411: powimagraw(GEN x, long n)
1412: {
1.2 ! noro 1413: gpmem_t av = avma;
! 1414: long m;
1.1 noro 1415: GEN y;
1416:
1417: if (typ(x) != t_QFI)
1418: err(talker,"not an imaginary quadratic form in powimag");
1419: if (!n) return imag_unit_form(x);
1420: if (n== 1) return gcopy(x);
1421: if (n==-1) return ginv(x);
1422:
1423: y = NULL; m=labs(n);
1424: for (; m>1; m>>=1)
1425: {
1426: if (m&1) y = y? compimagraw(y,x): x;
1427: x=sqcompimagraw(x);
1428: }
1429: y = y? compimagraw(y,x): x;
1430: if (n<0) y = ginv(y);
1431: return gerepileupto(av,y);
1432: }
1433:
1434: GEN
1435: powraw(GEN x, long n)
1436: {
1437: return (typ(x)==t_QFI)? powimagraw(x,n): powrealraw(x,n);
1438: }
1439:
1440: /* composition: Shanks' NUCOMP & NUDUPL */
1441: /* l = floor((|d|/4)^(1/4)) */
1442: GEN
1443: nucomp(GEN x, GEN y, GEN l)
1444: {
1.2 ! noro 1445: gpmem_t av=avma,tetpil;
! 1446: long cz;
1.1 noro 1447: GEN a,a1,a2,b,b2,d,d1,e,g,n,p1,p2,p3,q1,q2,q3,q4,s,t2,t3,u,u1,v,v1,v2,v3,z;
1448:
1449: if (x==y) return nudupl(x,l);
1450: if (typ(x) != t_QFI || typ(y) != t_QFI)
1451: err(talker,"not an imaginary quadratic form in nucomp");
1452:
1453: if (cmpii((GEN)x[1],(GEN)y[1]) < 0) { s=x; x=y; y=s; }
1454: s=shifti(addii((GEN)x[2],(GEN)y[2]),-1); n=subii((GEN)y[2],s);
1455: a1=(GEN)x[1]; a2=(GEN)y[1]; d=bezout(a2,a1,&u,&v);
1456: if (gcmp1(d)) { a=negi(gmul(u,n)); d1=d; }
1457: else
1458: if (divise(s,d))
1459: {
1460: a=negi(gmul(u,n)); d1=d; a1=divii(a1,d1);
1461: a2=divii(a2,d1); s=divii(s,d1);
1462: }
1463: else
1464: {
1465: d1=bezout(s,d,&u1,&v1);
1466: if (!gcmp1(d1))
1467: {
1468: a1=divii(a1,d1); a2=divii(a2,d1);
1469: s=divii(s,d1); d=divii(d,d1);
1470: }
1471: p1=resii((GEN)x[3],d); p2=resii((GEN)y[3],d);
1472: p3=modii(negi(mulii(u1,addii(mulii(u,p1),mulii(v,p2)))),d);
1473: a=subii(mulii(p3,divii(a1,d)),mulii(u,divii(n,d)));
1474: }
1475: a=modii(a,a1); p1=subii(a1,a); if (cmpii(a,p1)>0) a=negi(p1);
1476: v=gzero; d=a1; v2=gun; v3=a;
1477: for (cz=0; absi_cmp(v3,l) > 0; cz++)
1478: {
1479: p1=dvmdii(d,v3,&t3); t2=subii(v,mulii(p1,v2));
1480: v=v2; d=v3; v2=t2; v3=t3;
1481: }
1482: z=cgetg(4,t_QFI);
1483: if (!cz)
1484: {
1485: q1=mulii(a2,v3); q2=addii(q1,n);
1486: g=divii(addii(mulii(v3,s),(GEN)y[3]),d);
1487: z[1]=lmulii(d,a2);
1488: z[2]=laddii(shifti(q1,1),(GEN)y[2]);
1489: z[3]=laddii(mulii(v3,divii(q2,d)), mulii(g,d1));
1490: }
1491: else
1492: {
1493: if (cz&1) { v3=negi(v3); v2=negi(v2); }
1494: b=divii(addii(mulii(a2,d),mulii(n,v)),a1);
1495: q1=mulii(b,v3); q2=addii(q1,n);
1496: e=divii(addii(mulii(s,d),mulii((GEN)y[3],v)),a1);
1497: q3=mulii(e,v2); q4=subii(q3,s);
1498: g=divii(q4,v); b2=addii(q3,q4);
1499: if (!gcmp1(d1)) { v2=mulii(d1,v2); v=mulii(d1,v); b2=mulii(d1,b2); }
1500: z[1]=laddii(mulii(d,b),mulii(e,v));
1501: z[2]=laddii(b2,addii(q1,q2));
1502: z[3]=laddii(mulii(v3,divii(q2,d)), mulii(g,v2));
1503: }
1504: tetpil=avma; return gerepile(av,tetpil,redimag(z));
1505: }
1506:
1507: GEN
1508: nudupl(GEN x, GEN l)
1509: {
1.2 ! noro 1510: gpmem_t av=avma,tetpil;
! 1511: long cz;
1.1 noro 1512: GEN u,v,d,d1,p1,a,b,c,b2,z,v2,v3,t2,t3,e,g;
1513:
1514: if (typ(x) != t_QFI)
1515: err(talker,"not an imaginary quadratic form in nudupl");
1516: d1=bezout((GEN)x[2],(GEN)x[1],&u,&v);
1517: a=divii((GEN)x[1],d1); b=divii((GEN)x[2],d1);
1518: c=modii(negi(mulii(u,(GEN)x[3])),a); p1=subii(a,c);
1519: if (cmpii(c,p1)>0) c=negi(p1);
1520: v=gzero; d=a; v2=gun; v3=c;
1521: for (cz=0; absi_cmp(v3,l) > 0; cz++)
1522: {
1523: p1=dvmdii(d,v3,&t3); t2=subii(v,mulii(p1,v2));
1524: v=v2; d=v3; v2=t2; v3=t3;
1525: }
1526: z=cgetg(4,t_QFI);
1527: if (!cz)
1528: {
1529: g=divii(addii(mulii(v3,b),(GEN)x[3]),d);
1530: z[1]=(long)sqri(d);
1531: z[2]=laddii((GEN)x[2],shifti(mulii(d,v3),1));
1532: z[3]=laddii(sqri(v3),mulii(g,d1));
1533: }
1534: else
1535: {
1536: if (cz&1) { v=negi(v); d=negi(d); }
1537: e=divii(addii(mulii((GEN)x[3],v),mulii(b,d)),a);
1538: g=divii(subii(mulii(e,v2),b),v);
1539: b2=addii(mulii(e,v2),mulii(v,g));
1540: if (!gcmp1(d1)) { v2=mulii(d1,v2); v=mulii(d1,v); b2=mulii(d1,b2); }
1541: z[1]=laddii(sqri(d),mulii(e,v));
1542: z[2]=laddii(b2,shifti(mulii(d,v3),1));
1543: z[3]=laddii(sqri(v3),mulii(g,v2));
1544: }
1545: tetpil=avma; return gerepile(av,tetpil,redimag(z));
1546: }
1547:
1548: GEN
1549: nupow(GEN x, GEN n)
1550: {
1.2 ! noro 1551: gpmem_t av,tetpil;
! 1552: long i,j;
1.1 noro 1553: unsigned long m;
1554: GEN y,l;
1555:
1556: if (typ(n) != t_INT) err(talker,"not an integer exponent in nupow");
1557: if (gcmp1(n)) return gcopy(x);
1558: av=avma; y = imag_unit_form(x);
1559: if (!signe(n)) return y;
1560:
1561: l = racine(shifti(racine((GEN)y[3]),1));
1562: for (i=lgefint(n)-1; i>2; i--)
1563: for (m=n[i],j=0; j<BITS_IN_LONG; j++,m>>=1)
1564: {
1565: if (m&1) y=nucomp(y,x,l);
1566: x=nudupl(x,l);
1567: }
1568: for (m=n[2]; m>1; m>>=1)
1569: {
1570: if (m&1) y=nucomp(y,x,l);
1571: x=nudupl(x,l);
1572: }
1573: tetpil=avma; y=nucomp(y,x,l);
1574: if (signe(n)<0 && !egalii((GEN)y[1],(GEN)y[2])
1575: && !egalii((GEN)y[1],(GEN)y[3]))
1576: setsigne(y[2],-signe(y[2]));
1577: return gerepile(av,tetpil,y);
1578: }
1579:
1580: /* reduction */
1581:
1582: static GEN
1583: abs_dvmdii(GEN b, GEN p1, GEN *pt, long s)
1584: {
1585: if (s<0) setsigne(b, 1); p1 = dvmdii(b,p1,pt);
1586: if (s<0) setsigne(b,-1); return p1;
1587: }
1588:
1589: static GEN
1590: rhoimag0(GEN x, long *flag)
1591: {
1592: GEN p1,b,d,z;
1593: long fl, s = signe(x[2]);
1594:
1595: fl = cmpii((GEN)x[1], (GEN)x[3]);
1596: if (fl <= 0)
1597: {
1598: long fg = absi_cmp((GEN)x[1], (GEN)x[2]);
1599: if (fg >= 0)
1600: {
1601: *flag = (s<0 && (!fl || !fg))? 2 /* set x[2] = negi(x[2]) in caller */
1602: : 1;
1603: return x;
1604: }
1605: }
1606: p1=shifti((GEN)x[3],1); d = abs_dvmdii((GEN)x[2],p1,&b,s);
1607: if (s>=0)
1608: {
1609: setsigne(d,-signe(d));
1610: if (cmpii(b,(GEN)x[3])<=0) setsigne(b,-signe(b));
1611: else { d=addsi(-1,d); b=subii(p1,b); }
1612: }
1613: else if (cmpii(b,(GEN)x[3])>=0) { d=addsi(1,d); b=subii(b,p1); }
1614:
1615: z=cgetg(4,t_QFI);
1616: z[1] = x[3];
1617: z[3] = laddii((GEN)x[1], mulii(d,shifti(subii((GEN)x[2],b),-1)));
1618: if (signe(b)<0 && !fl) setsigne(b,1);
1619: z[2] = (long)b; *flag = 0; return z;
1620: }
1621:
1622: static void
1623: fix_expo(GEN x)
1624: {
1625: long e = expo(x[5]);
1626: if (e >= EXP220)
1627: {
1628: x[4] = laddsi(1,(GEN)x[4]);
1629: setexpo(x[5], e - EXP220);
1630: }
1631: }
1632:
1633: GEN
1634: rhoreal_aux(GEN x, GEN D, GEN sqrtD, GEN isqrtD)
1635: {
1636: GEN p1,p2, y = cgetg(6,t_VEC);
1637: GEN b = (GEN)x[2];
1638: GEN c = (GEN)x[3];
1639:
1640: y[1] = (long)c;
1.2 ! noro 1641: p2 = (absi_cmp(isqrtD,c) >= 0)? isqrtD: absi(c);
1.1 noro 1642: p1 = shifti(c,1);
1.2 ! noro 1643: if (p1 == gzero) err(talker, "reducible form in rhoreal");
! 1644: setsigne(p1,1); /* |2c| */
1.1 noro 1645: p2 = divii(addii(p2,b), p1);
1646: y[2] = lsubii(mulii(p2,p1), b);
1647:
1648: p1 = shifti(subii(sqri((GEN)y[2]),D),-2);
1649: y[3] = ldivii(p1,(GEN)y[1]);
1650:
1651: if (lg(x) <= 5) setlg(y,4);
1652: else
1653: {
1654: y[4] = x[4];
1655: y[5] = x[5];
1656: if (signe(b))
1657: {
1658: p1 = divrr(addir(b,sqrtD), subir(b,sqrtD));
1659: y[5] = lmulrr(p1, (GEN)y[5]);
1660: fix_expo(y);
1661: }
1662: }
1663: return y;
1664: }
1665:
1666: #define qf_NOD 2
1667: #define qf_STEP 1
1668:
1669: GEN
1670: codeform5(GEN x, long prec)
1671: {
1672: GEN y = cgetg(6,t_VEC);
1.2 ! noro 1673: y[1] = x[1];
! 1674: y[2] = x[2];
! 1675: y[3] = x[3];
! 1676: y[4] = zero;
! 1677: y[5] = (long)realun(prec); return y;
1.1 noro 1678: }
1679:
1680: static GEN
1681: add_distance(GEN x, GEN d0)
1682: {
1683: GEN y = cgetg(5, t_QFR);
1684: y[1] = licopy((GEN)x[1]);
1685: y[2] = licopy((GEN)x[2]);
1686: y[3] = licopy((GEN)x[3]);
1687: y[4] = lcopy(d0); return y;
1688: }
1689:
1690: /* d0 = initial distance, assume |n| > 1 */
1691: static GEN
1692: decodeform(GEN x, GEN d0)
1693: {
1694: GEN p1,p2;
1695:
1696: if (lg(x) < 6) return add_distance(x,d0);
1697: /* x = (a,b,c, expo(d), d), d = exp(2*distance) */
1698: p1 = absr((GEN)x[5]);
1699: p2 = (GEN)x[4];
1700: if (signe(p2))
1701: {
1702: long e = expo(p1);
1703: p1 = shiftr(p1,-e);
1704: p2 = addis(mulsi(EXP220,p2), e);
1705: p1 = mplog(p1);
1.2 ! noro 1706: p1 = mpadd(p1, mulir(p2, mplog2(lg(d0))));
1.1 noro 1707: }
1708: else
1709: { /* to avoid loss of precision */
1710: p1 = gcmp1(p1)? NULL: mplog(p1);
1711: }
1712: if (p1)
1713: d0 = addrr(d0, shiftr(p1,-1));
1714: return add_distance(x, d0);
1715: }
1716:
1717: static long
1718: get_prec(GEN d)
1719: {
1720: long k = lg(d);
1721: long l = ((BITS_IN_LONG-1-expo(d))>>TWOPOTBITS_IN_LONG)+2;
1722: if (l < k) l = k;
1723: if (l < 3) l = 3;
1724: return l;
1725: }
1726:
1727: static int
1728: real_isreduced(GEN x, GEN isqrtD)
1729: {
1730: GEN a = (GEN)x[1];
1731: GEN b = (GEN)x[2];
1732: if (signe(b) > 0 && cmpii(b,isqrtD) <= 0 )
1733: {
1734: GEN p1 = subii(isqrtD, shifti(absi(a),1));
1735: long l = absi_cmp(b, p1);
1736: if (l > 0 || (l == 0 && signe(p1) < 0)) return 1;
1737: }
1738: return 0;
1739: }
1740:
1741: GEN
1742: redrealform5(GEN x, GEN D, GEN sqrtD, GEN isqrtD)
1743: {
1744: while (!real_isreduced(x,isqrtD))
1745: x = rhoreal_aux(x,D,sqrtD,isqrtD);
1746: return x;
1747: }
1748:
1749: static GEN
1750: redreal0(GEN x, long flag, GEN D, GEN isqrtD, GEN sqrtD)
1751: {
1.2 ! noro 1752: gpmem_t av = avma;
! 1753: long prec;
1.1 noro 1754: GEN d0;
1755:
1756: if (typ(x) != t_QFR) err(talker,"not a real quadratic form in redreal");
1757:
1758: if (!D)
1759: D = qf_disc(x,NULL,NULL);
1760: else
1761: if (typ(D) != t_INT) err(arither1);
1762:
1763: d0 = (GEN)x[4]; prec = get_prec(d0);
1764: x = codeform5(x,prec);
1765: if ((flag & qf_NOD)) setlg(x,4);
1766: else
1767: {
1768: if (!sqrtD)
1769: sqrtD = gsqrt(D,prec);
1770: else
1771: {
1772: long l = typ(sqrtD);
1773: if (!is_intreal_t(l)) err(arither1);
1774: }
1775: }
1776: if (!isqrtD)
1777: isqrtD = sqrtD? mptrunc(sqrtD): racine(D);
1778: else
1779: if (typ(isqrtD) != t_INT) err(arither1);
1780:
1781: if (flag & qf_STEP)
1782: x = rhoreal_aux(x,D,sqrtD,isqrtD);
1783: else
1784: x = redrealform5(x,D,sqrtD,isqrtD);
1785: return gerepileupto(av, decodeform(x,d0));
1786: }
1787:
1788: GEN
1789: comprealform5(GEN x, GEN y, GEN D, GEN sqrtD, GEN isqrtD)
1790: {
1.2 ! noro 1791: gpmem_t av = avma;
1.1 noro 1792: GEN z = cgetg(6,t_VEC); comp_gen(z,x,y);
1793: if (x == y)
1794: {
1795: z[4] = lshifti((GEN)x[4],1);
1796: z[5] = lsqr((GEN)x[5]);
1797: }
1798: else
1799: {
1800: z[4] = laddii((GEN)x[4],(GEN)y[4]);
1801: z[5] = lmulrr((GEN)x[5],(GEN)y[5]);
1802: }
1803: fix_expo(z); z = redrealform5(z,D,sqrtD,isqrtD);
1804: return gerepilecopy(av,z);
1805: }
1806:
1807: /* assume n!=0 */
1808: GEN
1809: powrealform(GEN x, GEN n)
1810: {
1.2 ! noro 1811: gpmem_t av = avma;
! 1812: long i,m;
1.1 noro 1813: GEN y,D,sqrtD,isqrtD,d0;
1814:
1815: if (typ(x) != t_QFR)
1816: err(talker,"not a real quadratic form in powreal");
1817: if (gcmp1(n)) return gcopy(x);
1818: if (gcmp_1(n)) return ginv(x);
1819:
1820: d0 = (GEN)x[4];
1821: D = qf_disc(x,NULL,NULL);
1822: sqrtD = gsqrt(D, get_prec(d0));
1823: isqrtD = mptrunc(sqrtD);
1824: if (signe(n) < 0) { x = ginv(x); d0 = (GEN)x[4]; }
1825: n = absi(n);
1826: x = codeform5(x, lg(d0)); y = NULL;
1827: for (i=lgefint(n)-1; i>1; i--)
1828: {
1829: m = n[i];
1830: for (; m; m>>=1)
1831: {
1832: if (m&1) y = y? comprealform5(y,x,D,sqrtD,isqrtD): x;
1833: if (m == 1 && i == 2) break;
1834: x = comprealform5(x,x,D,sqrtD,isqrtD);
1835: }
1836: }
1837: d0 = mulri(d0,n);
1838: return gerepileupto(av, decodeform(y,d0));
1839: }
1840:
1841: GEN
1842: redimag(GEN x)
1843: {
1.2 ! noro 1844: gpmem_t av=avma;
! 1845: long fl;
1.1 noro 1846: do x = rhoimag0(x, &fl); while (fl == 0);
1847: x = gerepilecopy(av,x);
1848: if (fl == 2) setsigne(x[2], -signe(x[2]));
1849: return x;
1850: }
1851:
1852: GEN
1853: redreal(GEN x)
1854: {
1855: return redreal0(x,0,NULL,NULL,NULL);
1856: }
1857:
1858: GEN
1859: rhoreal(GEN x)
1860: {
1861: return redreal0(x,qf_STEP,NULL,NULL,NULL);
1862: }
1863:
1864: GEN
1865: redrealnod(GEN x, GEN isqrtD)
1866: {
1867: return redreal0(x,qf_NOD,NULL,isqrtD,NULL);
1868: }
1869:
1870: GEN
1871: rhorealnod(GEN x, GEN isqrtD)
1872: {
1873: return redreal0(x,qf_STEP|qf_NOD,NULL,isqrtD,NULL);
1874: }
1875:
1876: GEN
1877: qfbred0(GEN x, long flag, GEN D, GEN isqrtD, GEN sqrtD)
1878: {
1879: long tx=typ(x),fl;
1.2 ! noro 1880: gpmem_t av;
1.1 noro 1881:
1882: if (!is_qf_t(tx)) err(talker,"not a quadratic form in qfbred");
1883: if (!D) D = qf_disc(x,NULL,NULL);
1884: switch(signe(D))
1885: {
1886: case 1 :
1887: return redreal0(x,flag,D,isqrtD,sqrtD);
1888:
1889: case -1:
1890: if (!flag) return redimag(x);
1891: if (flag !=1) err(flagerr,"qfbred");
1892: av=avma; x = rhoimag0(x,&fl);
1893: x = gerepilecopy(av,x);
1894: if (fl == 2) setsigne(x[2], -signe(x[2]));
1895: return x;
1896: }
1897: err(redpoler,"qfbred");
1898: return NULL; /* not reached */
1899: }
1900:
1901: /* special case: p = 1 return unit form */
1902: GEN
1903: primeform(GEN x, GEN p, long prec)
1904: {
1.2 ! noro 1905: gpmem_t av;
! 1906: long s, sx = signe(x);
! 1907: GEN y, b, c;
1.1 noro 1908:
1.2 ! noro 1909: if (typ(x) != t_INT || !sx) err(arither1);
1.1 noro 1910: if (typ(p) != t_INT || signe(p) <= 0) err(arither1);
1911: if (is_pm1(p))
1.2 ! noro 1912: return sx<0? imag_unit_form_by_disc(x)
! 1913: : real_unit_form_by_disc(x,prec);
! 1914: s = mod8(x);
! 1915: if (sx < 0)
1.1 noro 1916: {
1.2 ! noro 1917: if (s) s = 8-s;
! 1918: y = cgetg(4, t_QFI);
1.1 noro 1919: }
1920: else
1921: {
1.2 ! noro 1922: y = cgetg(5, t_QFR);
! 1923: y[4] = (long)realzero(prec);
1.1 noro 1924: }
1925: switch(s&3)
1926: {
1927: case 2: case 3: err(funder2,"primeform");
1928: }
1.2 ! noro 1929: av = avma;
! 1930: if (egalii(p, gdeux))
1.1 noro 1931: {
1932: switch(s)
1933: {
1.2 ! noro 1934: case 0: b = gzero; break;
! 1935: case 1: b = gun; break;
! 1936: case 4: b = gdeux; break;
! 1937: default: err(sqrter5); b = NULL; /* -Wall */
1.1 noro 1938: }
1.2 ! noro 1939: c = shifti(subsi(s,x), -3);
1.1 noro 1940: }
1941: else
1942: {
1943: b = mpsqrtmod(x,p); if (!b) err(sqrter5);
1.2 ! noro 1944: s &= 1; /* s = x mod 2 */
! 1945: /* mod(b) != mod2(x) ? [Warning: we may have b == 0] */
! 1946: if ((!signe(b) && s) || mod2(b) != s) b = gerepileuptoint(av, subii(p,b));
! 1947:
! 1948: av = avma;
! 1949: c = diviiexact(shifti(subii(sqri(b), x), -2), p);
! 1950: }
! 1951: y[3] = lpileuptoint(av, c);
! 1952: y[2] = (long)b;
! 1953: y[1] = licopy(p); return y;
1.1 noro 1954: }
1955:
1956: /*********************************************************************/
1957: /** **/
1958: /** BINARY DECOMPOSITION **/
1959: /** **/
1960: /*********************************************************************/
1961:
1962: GEN
1963: binaire(GEN x)
1964: {
1965: ulong m,u;
1966: long i,lx,ex,ly,tx=typ(x);
1967: GEN y,p1,p2;
1968:
1969: switch(tx)
1970: {
1971: case t_INT:
1972: lx=lgefint(x);
1973: if (lx==2) { y=cgetg(2,t_VEC); y[1]=zero; return y; }
1974: ly = BITS_IN_LONG+1; m=HIGHBIT; u=x[2];
1975: while (!(m & u)) { m>>=1; ly--; }
1976: y = cgetg(ly+((lx-3)<<TWOPOTBITS_IN_LONG),t_VEC); ly=1;
1977: do { y[ly] = m & u ? un : zero; ly++; } while (m>>=1);
1978: for (i=3; i<lx; i++)
1979: {
1980: m=HIGHBIT; u=x[i];
1981: do { y[ly] = m & u ? un : zero; ly++; } while (m>>=1);
1982: }
1983: break;
1984:
1985: case t_REAL:
1986: ex=expo(x);
1987: if (!signe(x))
1988: {
1989: lx=1+max(-ex,0); y=cgetg(lx,t_VEC);
1990: for (i=1; i<lx; i++) y[i]=zero;
1991: return y;
1992: }
1993:
1994: lx=lg(x); y=cgetg(3,t_VEC);
1995: if (ex > bit_accuracy(lx)) err(precer,"binary");
1996: p1 = cgetg(max(ex,0)+2,t_VEC);
1997: p2 = cgetg(bit_accuracy(lx)-ex,t_VEC);
1998: y[1] = (long) p1; y[2] = (long) p2;
1999: ly = -ex; ex++; m = HIGHBIT;
2000: if (ex<=0)
2001: {
2002: p1[1]=zero; for (i=1; i <= -ex; i++) p2[i]=zero;
2003: i=2;
2004: }
2005: else
2006: {
2007: ly=1;
2008: for (i=2; i<lx && ly<=ex; i++)
2009: {
2010: m=HIGHBIT; u=x[i];
2011: do
2012: { p1[ly] = (m & u) ? un : zero; ly++; }
2013: while ((m>>=1) && ly<=ex);
2014: }
2015: ly=1;
2016: if (m) i--; else m=HIGHBIT;
2017: }
2018: for (; i<lx; i++)
2019: {
2020: u=x[i];
2021: do { p2[ly] = m & u ? un : zero; ly++; } while (m>>=1);
2022: m=HIGHBIT;
2023: }
2024: break;
2025:
2026: case t_VEC: case t_COL: case t_MAT:
2027: lx=lg(x); y=cgetg(lx,tx);
2028: for (i=1; i<lx; i++) y[i]=(long)binaire((GEN)x[i]);
2029: break;
2030: default: err(typeer,"binaire");
2031: return NULL; /* not reached */
2032: }
2033: return y;
2034: }
2035:
2036: /* return 1 if bit n of x is set, 0 otherwise */
2037: long
2038: bittest(GEN x, long n)
2039: {
2040: long l;
2041:
2042: if (!signe(x) || n<0) return 0;
2043: l = lgefint(x)-1 - (n>>TWOPOTBITS_IN_LONG);
2044: if (l < 2) return 0;
2045: n = (1L << (n & (BITS_IN_LONG-1))) & x[l];
2046: return n? 1: 0;
2047: }
2048:
1.2 ! noro 2049: GEN
! 2050: bittest_many(GEN x, GEN gn, long c)
! 2051: {
! 2052: long lx = lgefint(x), l1, l2, b1, b2, two_adic = 0, l_res, skip;
! 2053: ulong *p, *pnew;
! 2054: long n = itos(gn), extra_words = 0, partial_bits;
! 2055: GEN res;
! 2056:
! 2057: if (c == 1) /* Shortcut */
! 2058: return bittest(x,n) ? gun : gzero;
! 2059: /* Negative n with n+c>0 are too hairy to implement... */
! 2060: if (!signe(x) || c == 0)
! 2061: return gzero;
! 2062: if (c < 0) { /* Negative x means 2s complemenent */
! 2063: c = -c;
! 2064: if (signe(x) < 0)
! 2065: two_adic = 1; /* treat x 2-adically... */
! 2066: }
! 2067: if (n < 0) {
! 2068: gpmem_t oa, na;
! 2069:
! 2070: if (n + c <= 0)
! 2071: return gzero;
! 2072: oa = avma;
! 2073: res = bittest_many(x, gzero, two_adic? -(n+c) : n+c);
! 2074: na = avma;
! 2075: res = shifti3(res,-n,0);
! 2076: return gerepile(oa,na,res);
! 2077: }
! 2078: partial_bits = (c & (BITS_IN_LONG-1));
! 2079: l2 = lx-1 - (n>>TWOPOTBITS_IN_LONG); /* Last=least-significant word */
! 2080: l1 = lx-1 - ((n + c - 1)>>TWOPOTBITS_IN_LONG); /* First word */
! 2081: b2 = (n & (BITS_IN_LONG-1)); /* Last bit, skip less-signifant */
! 2082: b1 = ((n + c - 1) & (BITS_IN_LONG-1)); /* First bit, skip more-significant */
! 2083: if (l2 < 2) { /* always: l1 <= l2 */
! 2084: if (!two_adic)
! 2085: return gzero;
! 2086: /* x is non-zero, so it behaves as -1. */
! 2087: return gbitneg(gzero,c);
! 2088: }
! 2089: if (l1 < 2) {
! 2090: if (two_adic) /* If b1 < b2, bits are set by prepend in shift_r */
! 2091: extra_words = 2 - l1 - (b1 < b2);
! 2092: else
! 2093: partial_bits = b2 ? BITS_IN_LONG - b2 : 0;
! 2094: l1 = 2;
! 2095: b1 = (BITS_IN_LONG-1); /* Include all bits in this word */
! 2096: }
! 2097: skip = (b1 < b2); /* Skip the first word of the shift */
! 2098: l_res = l2 - l1 + 1 + 2 - skip + extra_words; /* A coarse estimate */
! 2099: p = (ulong*) (new_chunk(l_res) + 2 + extra_words);
! 2100: shift_r(p - skip, (ulong*)x + l1, (ulong*)x + l2 + 1, 0, b2);
! 2101: if (two_adic) { /* Check the low bits of x */
! 2102: int i = lx, nonzero = 0;
! 2103:
! 2104: /* Flip the bits */
! 2105: pnew = p + l_res - 2 - extra_words;
! 2106: while (--pnew >= p)
! 2107: *pnew = MAXULONG - *pnew;
! 2108: /* Fill the extra words */
! 2109: while (extra_words--)
! 2110: *--p = MAXULONG;
! 2111: /* The result is one less than 2s-complement if the lower-bits
! 2112: of x were all 0. */
! 2113: while (--i > l2) {
! 2114: if (x[i]) {
! 2115: nonzero = 1;
! 2116: break;
! 2117: }
! 2118: }
! 2119: if (!nonzero && b2) /* Check the partial word too */
! 2120: nonzero = x[l2] & ((1<<b2) - 1);
! 2121: if (!nonzero) { /* Increment res. Do not underflow to before p */
! 2122: pnew = p + l_res - 2;
! 2123: while (--pnew >= p)
! 2124: if (++*pnew)
! 2125: break;
! 2126: }
! 2127: }
! 2128: if (partial_bits)
! 2129: *p &= (1<<partial_bits) - 1;
! 2130: pnew = p;
! 2131: while ((pnew < p + l_res - 2) && !*pnew) /* Skip 0 words */
! 2132: pnew++;
! 2133: avma = (gpmem_t)(pnew - 2);
! 2134: if (pnew >= p - 2 + l_res)
! 2135: return gzero;
! 2136: l_res -= (pnew - p);
! 2137: res = (GEN)(pnew - 2);
! 2138: res[1] = evalsigne(1)|evallgefint(l_res);
! 2139: res[0] = evaltyp(t_INT)|evallg(l_res);
! 2140: return res;
! 2141: }
! 2142:
1.1 noro 2143: static long
2144: bittestg(GEN x, GEN n)
2145: {
2146: return bittest(x,itos(n));
2147: }
2148:
2149: GEN
2150: gbittest(GEN x, GEN n)
2151: {
2152: return arith_proto2(bittestg,x,n);
2153: }
2154:
1.2 ! noro 2155: GEN
! 2156: gbittest3(GEN x, GEN n, long c)
! 2157: {
! 2158: return garith_proto3ggs(bittest_many,x,n,c);
! 2159: }
! 2160:
1.1 noro 2161: /***********************************************************************/
2162: /** **/
2163: /** BITMAP OPS **/
2164: /** x & y (and), x | y (or), x ^ y (xor), ~x (neg), x & ~y (negimply) **/
2165: /** **/
2166: /***********************************************************************/
2167:
2168: /* Normalize a non-negative integer. */
2169: static void
2170: inormalize(GEN x, long known_zero_words)
2171: {
2172: int xl = lgefint(x);
2173: int i, j;
2174:
2175: /* Normalize */
2176: i = 2 + known_zero_words;
2177: while (i < xl) {
2178: if (x[i])
2179: break;
2180: i++;
2181: }
2182: j = 2;
2183: while (i < xl)
2184: x[j++] = x[i++];
2185: xl -= i - j;
2186: setlgefint(x, xl);
2187: if (xl == 2)
2188: setsigne(x,0);
2189: }
2190:
2191: /* Truncate a non-negative integer to a number of bits. */
2192: static void
2193: ibittrunc(GEN x, long bits, long normalized)
2194: {
2195: int xl = lgefint(x);
2196: int len_out = ((bits + BITS_IN_LONG - 1) >> TWOPOTBITS_IN_LONG) + 2;
2197: int known_zero_words, i = 2 + xl - len_out;
2198:
2199: if (xl < len_out && normalized)
2200: return;
2201: /* Check whether mask is trivial */
2202: if (!(bits & (BITS_IN_LONG - 1))) {
2203: if (xl == len_out && normalized)
2204: return;
2205: } else if (len_out <= xl) {
2206: /* Non-trival mask is given by a formula, if x is not
2207: normalized, this works even in the exceptional case */
2208: x[i] = x[i] & ((1 << (bits & (BITS_IN_LONG - 1))) - 1);
2209: if (x[i] && xl == len_out)
2210: return;
2211: }
2212: /* Normalize */
2213: if (xl <= len_out) /* Not normalized */
2214: known_zero_words = 0;
2215: else
2216: known_zero_words = xl - len_out;
2217: inormalize(x, known_zero_words);
2218: }
2219:
2220: /* Increment/decrement absolute value of non-zero integer in place.
2221: It is assumed that the increment will not increase the length.
2222: Decrement may result in a non-normalized value.
2223: Returns 1 if the increment overflows (thus the result is 0). */
2224: static int
2225: incdec(GEN x, long incdec)
2226: {
2227: long *xf = x + 2, *xl;
2228: long len = lgefint(x);
2229: const ulong uzero = 0;
2230:
2231: xl = x + len;
2232: if (incdec == 1) {
2233: while (--xl >= xf) {
2234: if ((ulong)*xl != ~uzero) {
2235: (*xl)++;
2236: return 0;
2237: }
2238: *xl = 0;
2239: }
2240: return 1;
2241: } else {
2242: while (--xl >= xf) {
2243: if (*xl != 0) {
2244: (*xl)--;
2245: return 0;
2246: }
2247: *xl = (long)~uzero;
2248: }
2249: return 0;
2250: }
2251: }
2252:
2253: GEN
2254: gbitneg(GEN x, long bits)
2255: {
2256: long xl, len_out, i;
2257: const ulong uzero = 0;
2258:
2259: if (typ(x) != t_INT)
2260: err(typeer, "bitwise negation");
2261: if (bits < -1)
2262: err(talker, "negative exponent in bitwise negation");
2263: if (bits == -1)
2264: return gsub(gneg(gun),x);
2265: if (bits == 0)
2266: return gzero;
2267: if (signe(x) == -1) { /* Consider as if mod big power of 2 */
2268: x = gcopy(x);
2269: setsigne(x, 1);
2270: incdec(x, -1);
2271: /* Now truncate this! */
2272: ibittrunc(x, bits, x[2]);
2273: return x;
2274: }
2275: xl = lgefint(x);
2276: len_out = ((bits + BITS_IN_LONG - 1) >> TWOPOTBITS_IN_LONG) + 2;
2277: if (len_out > xl) { /* Need to grow */
2278: GEN out = cgeti(len_out);
2279: int j = 2;
2280:
2281: if (!(bits & (BITS_IN_LONG - 1)))
2282: out[2] = ~uzero;
2283: else
2284: out[2] = (1 << (bits & (BITS_IN_LONG - 1))) - 1;
2285: for (i = 3; i < len_out - xl + 2; i++)
2286: out[i] = ~uzero;
2287: while (i < len_out)
2288: out[i++] = ~x[j++];
2289: setlgefint(out, len_out);
2290: setsigne(out,1);
2291: return out;
2292: }
2293: x = gcopy(x);
2294: for (i = 2; i < xl; i++)
2295: x[i] = ~x[i];
2296: ibittrunc(x, bits, x[2]);
2297: return x;
2298: }
2299:
2300: /* bitwise 'and' of two positive integers (any integers, but we ignore sign).
2301: * Inputs are not necessary normalized. */
2302: static GEN
2303: ibitand(GEN x, GEN y)
2304: {
2305: long lx, ly, lout;
2306: long *xp, *yp, *outp, *xlim;
2307: GEN out;
2308:
2309: lx=lgefint(x); ly=lgefint(y);
2310: if (lx > ly)
2311: lout = ly;
2312: else
2313: lout = lx;
2314: xlim = x + lx;
2315: xp = xlim + 2 - lout;
2316: yp = y + 2 + ly - lout;
2317: out = cgeti(lout);
2318: outp = out + 2;
2319: while (xp < xlim)
2320: *outp++ = (*xp++) & (*yp++);
2321: setsigne(out,1);
2322: setlgefint(out,lout);
2323: if (lout == 2)
2324: setsigne(out,0);
2325: else if ( !out[2] )
2326: inormalize(out, 1);
2327: return out;
2328: }
2329:
2330: #define swaplen(x,y, nx,ny) {long _a=nx;GEN _z=x; nx=ny; ny=_a; x=y; y=_z;}
2331:
2332: /* bitwise 'or' of two positive integers (any integers, but we ignore sign).
2333: * Inputs are not necessary normalized. */
2334: static GEN
2335: ibitor(GEN x, GEN y, long exclusive)
2336: {
2337: long lx, ly, lout;
2338: long *xp, *yp, *outp, *xlim, *xprep;
2339: GEN out;
2340:
2341: lx=lgefint(x); ly=lgefint(y);
2342: if (lx < ly)
2343: swaplen(x,y,lx,ly);
2344: lout = lx;
2345: xlim = x + lx;
2346: xp = xlim + 2 - ly;
2347: yp = y + 2;
2348: out = cgeti(lout);
2349: outp = out + 2;
2350: if (lx > ly) {
2351: xprep = x + 2;
2352: while (xprep < xp)
2353: *outp++ = *xprep++;
2354: }
2355: if (exclusive) {
2356: while (xp < xlim)
2357: *outp++ = (*xp++) ^ (*yp++);
2358: } else {
2359: while (xp < xlim)
2360: *outp++ = (*xp++) | (*yp++);
2361: }
2362: setsigne(out,1);
2363: setlgefint(out,lout);
2364: if (lout == 2)
2365: setsigne(out,0);
2366: else if ( !out[2] )
2367: inormalize(out, 1);
2368: return out;
2369: }
2370:
2371: /* bitwise negated 'implies' of two positive integers (any integers, but we
2372: * ignore sign). "Neg-Implies" is x & ~y unless "negated".
2373: * Inputs are not necessary normalized. */
2374: static GEN
2375: ibitnegimply(GEN x, GEN y)
2376: {
2377: long lx, ly, lout, inverted = 0;
2378: long *xp, *yp, *outp, *xlim, *xprep;
2379: GEN out;
2380:
2381: lx=lgefint(x); ly=lgefint(y);
2382: if (lx < ly) {
2383: inverted = 1;
2384: swaplen(x,y,lx,ly);
2385: }
2386: /* x is longer than y */
2387: lout = lx;
2388: xlim = x + lx;
2389: xp = xlim + 2 - ly;
2390: yp = y + 2;
2391: out = cgeti(lout);
2392: outp = out + 2;
2393: if (lx > ly) {
2394: xprep = x + 2;
2395: if (!inverted) { /* x & ~y */
2396: while (xprep < xp)
2397: *outp++ = *xprep++;
2398: } else { /* ~x & y */
2399: while (xprep++ < xp)
2400: *outp++ = 0;
2401: }
2402: }
2403: if (inverted) { /* ~x & y */
2404: while (xp < xlim)
2405: *outp++ = ~(*xp++) & (*yp++);
2406: } else {
2407: while (xp < xlim)
2408: *outp++ = (*xp++) & ~(*yp++);
2409: }
2410: setsigne(out,1);
2411: setlgefint(out,lout);
2412: if (lout == 2)
2413: setsigne(out,0);
2414: else if ( !out[2] )
2415: inormalize(out, 1);
2416: return out;
2417: }
2418:
2419: static GEN
1.2 ! noro 2420: inegate_inplace(GEN z, gpmem_t ltop)
1.1 noro 2421: {
1.2 ! noro 2422: long o;
1.1 noro 2423:
2424: /* Negate z */
2425: o = incdec(z, 1); /* Can overflow z... */
2426: setsigne(z, -1);
2427: if (!o)
2428: return z;
2429: else if (lgefint(z) == 2)
2430: setsigne(z, 0);
2431: incdec(z,-1); /* Restore a normalized value */
1.2 ! noro 2432: return gerepileupto(ltop, subis(z,1));
1.1 noro 2433: }
2434:
2435: GEN
2436: gbitor(GEN x, GEN y)
2437: {
1.2 ! noro 2438: gpmem_t ltop;
1.1 noro 2439: long sx,sy;
2440: GEN z;
2441:
2442: if (typ(x) != t_INT || typ(y) != t_INT)
2443: err(typeer, "bitwise or");
2444: sx=signe(x); if (!sx) return icopy(y);
2445: sy=signe(y); if (!sy) return icopy(x);
2446: if (sx == 1) {
2447: if (sy == 1)
2448: return ibitor(x,y,0);
2449: goto posneg;
2450: } else if (sy == -1) {
2451: ltop = avma;
2452: incdec(x, -1); incdec(y, -1);
2453: z = ibitand(x,y);
2454: incdec(x, 1); incdec(y, 1); /* Restore x and y... */
2455: } else {
2456: z = x; x = y; y = z;
2457: /* x is positive, y is negative. The result will be negative. */
2458: posneg:
2459: ltop = avma;
2460: incdec(y, -1);
2461: z = ibitnegimply(y,x); /* ~x & y */
2462: incdec(y, 1);
2463: }
2464: return inegate_inplace(z, ltop);
2465: }
2466:
2467: GEN
2468: gbitand(GEN x, GEN y)
2469: {
1.2 ! noro 2470: gpmem_t ltop;
1.1 noro 2471: long sx,sy;
2472: GEN z;
2473:
2474: if (typ(x) != t_INT || typ(y) != t_INT)
2475: err(typeer, "bitwise and");
2476: sx=signe(x); if (!sx) return gzero;
2477: sy=signe(y); if (!sy) return gzero;
2478: if (sx == 1) {
2479: if (sy == 1)
2480: return ibitand(x,y);
2481: goto posneg;
2482: } else if (sy == -1) {
2483: ltop = avma;
2484: incdec(x, -1); incdec(y, -1);
2485: z = ibitor(x,y,0);
2486: incdec(x, 1); incdec(y, 1); /* Restore x and y... */
2487: return inegate_inplace(z, ltop);
2488: } else {
2489: z = x; x = y; y = z;
2490: /* x is positive, y is negative. The result will be positive. */
2491: posneg:
2492: ltop = avma;
2493: incdec(y, -1);
2494: /* x & ~y */
2495: z = ibitnegimply(x,y); /* x & ~y */
2496: incdec(y, 1);
2497: return z;
2498: }
2499: }
2500:
2501: GEN
2502: gbitxor(GEN x, GEN y)
2503: {
1.2 ! noro 2504: gpmem_t ltop;
1.1 noro 2505: long sx,sy;
2506: GEN z;
2507:
2508: if (typ(x) != t_INT || typ(y) != t_INT)
2509: err(typeer, "bitwise xor");
2510: sx=signe(x); if (!sx) return icopy(y);
2511: sy=signe(y); if (!sy) return icopy(x);
2512: if (sx == 1) {
2513: if (sy == 1)
2514: return ibitor(x,y,1);
2515: goto posneg;
2516: } else if (sy == -1) {
2517: incdec(x, -1); incdec(y, -1);
2518: z = ibitor(x,y,1);
2519: incdec(x, 1); incdec(y, 1); /* Restore x and y... */
2520: return z;
2521: } else {
2522: z = x; x = y; y = z;
2523: /* x is positive, y is negative. The result will be negative. */
2524: posneg:
2525: ltop = avma;
2526: incdec(y, -1);
2527: /* ~(x ^ ~y) == x ^ y */
2528: z = ibitor(x,y,1);
2529: incdec(y, 1);
2530: }
2531: return inegate_inplace(z, ltop);
2532: }
2533:
2534: GEN
2535: gbitnegimply(GEN x, GEN y) /* x & ~y */
2536: {
1.2 ! noro 2537: gpmem_t ltop;
1.1 noro 2538: long sx,sy;
2539: GEN z;
2540:
2541: if (typ(x) != t_INT || typ(y) != t_INT)
2542: err(typeer, "bitwise negated imply");
2543: sx=signe(x); if (!sx) return gzero;
2544: sy=signe(y); if (!sy) return icopy(x);
2545: if (sx == 1) {
2546: if (sy == 1)
2547: return ibitnegimply(x,y);
2548: /* x is positive, y is negative. The result will be positive. */
2549: incdec(y, -1);
2550: z = ibitand(x,y);
2551: incdec(y, 1);
2552: return z;
2553: } else if (sy == -1) {
2554: /* both negative. The result will be positive. */
2555: incdec(x, -1); incdec(y, -1);
2556: /* ((~x) & ~(~y)) == ~x & y */
2557: z = ibitnegimply(y,x);
2558: incdec(x, 1); incdec(y, 1); /* Restore x and y... */
2559: return z;
2560: } else {
2561: /* x is negative, y is positive. The result will be negative. */
2562: ltop = avma;
2563: incdec(x, -1);
2564: /* ~((~x) & ~y) == x | y */
2565: z = ibitor(x,y,0);
2566: incdec(x, 1);
2567: }
2568: return inegate_inplace(z, ltop);
2569: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>