// -*- mode:C++ ; compile-command: "g++-3.4 -I.. -g -c ifactor.cc -DHAVE_CONFIG_H -DIN_GIAC" -*- #include "giacPCH.h" #ifndef __MINGW_H #define GIAC_MPQS // define if you want to use giac for sieving #endif #include "path.h" /* * Copyright (C) 2003,14 R. De Graeve & B. Parisse, * Institut Fourier, 38402 St Martin d'Heres * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ using namespace std; #ifdef GIAC_HAS_STO_38 //#undef clock //#undef clock_t #else #include //#include // For reading arguments from file #include "ifactor.h" #include "pari.h" #include "usual.h" #include "sym2poly.h" #include "rpn.h" #include "prog.h" #include "misc.h" #include "giacintl.h" #endif #ifdef GIAC_HAS_STO_38 #define BESTA_OS #endif // Trying to make ifactor(2^128+1) work on ARM #if defined(RTOS_THREADX) || defined(BESTA_OS) || defined NSPIRE //#define OLD_AFACT #define GIAC_ADDITIONAL_PRIMES 16// if defined, additional primes are used in sieve #else #define GIAC_ADDITIONAL_PRIMES 32// if defined, additional primes are used in sieve #endif #ifndef NO_NAMESPACE_GIAC namespace giac { #endif // ndef NO_NAMESPACE_GIAC #if 0 struct int256 { longlong a; ulonglong b,c,d; }; struct int128 { longlong a; ulonglong b; }; void sub(int256 A,int b,int256 & C){ bool Apos=A.a>=0; if (Apos){ if (b<0){ add(A,b,C); return; } bool carry=A.d=0; if (Apos){ if (b<0){ sub(A,-b,C); return; } A.d += b; if (A.d>32; p1=A1; p = p1*p2; p += C1; unsigned short carry = (p>32; C2 += carry; carry = (C2 & crible,unsigned p){ crible.resize((p-1)/64+1); unsigned cs=crible.size(); unsigned lastnum=64*cs; unsigned lastsieve=int(std::sqrt(double(lastnum))); unsigned primesieved=1; crible[0] = 0xfffffffe; // 1 is not prime and not sieved (2 is not sieved) for (unsigned i=1;i & crible,unsigned p){ // assumes crible has been filled ++p; if (p%2==0) ++p; unsigned pos=(p-1)/2,cs=crible.size()*32; if (2*cs+1<=p) return nextprime(int(p)).val; for (;pos static void printbool(nio::ios_base & os,const vector & v,int C=1){ if (C) C=giacmin(C,int(v.size())); else C=v.size(); for (int c=0;c> s & 1)==1)?1:0) << " "; } } os << endl; } template void printbool(nio::ios_base & os,const vector< vector > & m,int L=32){ if (L) L=giacmin(L,int(m.size())); else L=m.size(); for (int l=0;l & v,int C=1){ if (C) C=giacmin(C,int(v.size())); else C=int(v.size()); for (int c=0;c> s & 1)==1)?1:0) << " "; } } os << endl; } void printbool(ostream & os,const vector< vector > & m,int L=32){ if (L) L=giacmin(L,int(m.size())); else L=int(m.size()); for (int l=0;l inline void swap(T * & ptr1, T * & ptr2){ T * tmp=ptr1; ptr1=ptr2; ptr2=tmp; } #ifdef x86_64 #define GIAC_RREF_UNROLL 4 #else #define GIAC_RREF_UNROLL 4 #endif // #define RREF_SORT #ifdef RREF_SORT struct line_t { unsigned * tab; unsigned count; }; bool operator < (const line_t & l1,const line_t & l2){ if (!l1.count) return false; if (!l2.count) return true; return l1.count>= 1; } } return r; } #else struct line_t { unsigned * tab; }; #endif // mode=0: full reduction, 1 subreduction, 2 finish full reduction from subreduction void rref(vector< line_t > & m,int L,int C32,int mode){ int i,l=0,c=0,C=C32*32; for (;l> c2) & 1) break; } if (i==L){ // none found in this column ++c; continue; } if (i!=l) swap(m[i].tab,m[l].tab); // don't care about count... int start=mode==1?l+1:0, end=mode==2?l:L; #ifdef x86_64 ulonglong * pivend, * pivbeg; pivbeg = (ulonglong *) (m[l].tab+(c1/GIAC_RREF_UNROLL)*GIAC_RREF_UNROLL); pivend = (ulonglong *) (m[l].tab+C32); #else unsigned * pivbeg = m[l].tab+(c1/GIAC_RREF_UNROLL)*GIAC_RREF_UNROLL, * pivend = m[l].tab+C32; #endif for (i=start;i> c2) & 1)!=1) continue; // line combination l and i #ifdef x86_64 ulonglong * curptr=(ulonglong *) (m[i].tab+(c1/GIAC_RREF_UNROLL)*GIAC_RREF_UNROLL); for (ulonglong * pivptr=pivbeg;pivptr!=pivend;curptr += GIAC_RREF_UNROLL/2,pivptr += GIAC_RREF_UNROLL/2){ // small optimization (loop unroll), assumes mult of 4(*32) columns // PREFETCH(curptr+8); *curptr ^= *pivptr; curptr[1] ^= pivptr[1]; #if GIAC_RREF_UNROLL==8 curptr[2] ^= pivptr[2]; curptr[3] ^= pivptr[3]; #endif } #else unsigned * curptr=m[i].tab+(c1/GIAC_RREF_UNROLL)*GIAC_RREF_UNROLL; for (unsigned * pivptr=pivbeg;pivptr!=pivend;curptr += GIAC_RREF_UNROLL,pivptr += GIAC_RREF_UNROLL){ // small optimization (loop unroll), assumes mult of 4(*32) columns // PREFETCH(curptr+16); *curptr ^= *pivptr; curptr[1] ^= pivptr[1]; curptr[2] ^= pivptr[2]; curptr[3] ^= pivptr[3]; #if GIAC_RREF_UNROLL==8 curptr[4] ^= pivptr[4]; curptr[5] ^= pivptr[5]; curptr[6] ^= pivptr[6]; curptr[7] ^= pivptr[7]; #endif } #endif } ++l; ++c; } } template void release_memory(vector & slice){ // release memory from slice vector tmp; swap(slice,tmp); } #ifdef USE_GMP_REPLACEMENTS int modulo(const mpz_t & a,unsigned b){ if (mpz_cmp_ui(a,0)<0){ mpz_neg(*(mpz_t *)&a,a); int res=modulo(a,b); mpz_neg(*(mpz_t *)&a,a); return b-res; } mp_digit C; mp_mod_d((mp_int *)&a,b,&C); return C; } #else int modulo(const mpz_t & a,unsigned b){ return mpz_fdiv_ui(a,b); } #endif #if defined RTOS_THREADX || defined BESTA_OS || defined NSPIRE typedef unsigned short pui_t ; typedef unsigned short ushort_t; typedef short short_t; #else typedef unsigned pui_t ; // #ifndef USE_GMP_REPLACEMENTS // uncomment for Aspen debugging #define PRIMES32 // #endif #ifdef PRIMES32 typedef unsigned ushort_t; typedef int short_t; #else typedef unsigned short ushort_t; typedef unsigned short int short_t; #endif #ifdef EMCC #include #endif #if (defined EMCC || defined(HASH_MAP_NAMESPACE)) && defined(PRIMES32) #define ADDITIONAL_PRIMES_HASHMAP #endif #endif // RTOS_THREADX || BESTA_OS struct axbinv { #if 0 unsigned short aindex; unsigned short bindex; #else unsigned aindex; unsigned bindex; #endif int shiftpos; pui_t first,second; // indexes in the "puissancestab" table axbinv(ushort_t a_,int shiftpos_,ushort_t b_,pui_t f_,pui_t s_):aindex(a_),bindex(b_),shiftpos(shiftpos_),first(f_),second(s_) {}; axbinv() {}; }; #ifdef ADDITIONAL_PRIMES_HASHMAP unsigned largep(const axbinv & A,ushort_t * puissancestab) { // return A.largeprime; if (A.second-A.first<3) return 0; #ifdef PRIMES32 if (*(puissancestab+A.second-2)!=1) return 0; return *(puissancestab+A.second-1); #else if (*(puissancestab+A.second-3)!=1) return 0; return (unsigned(*(puissancestab+A.second-2)) << 16) + *(puissancestab+A.second-1); #endif } #endif #ifdef ADDITIONAL_PRIMES_HASHMAP #ifdef EMCC // container does not seem to be important for <= 70 digits typedef map additional_map_t; #else typedef HASH_MAP_NAMESPACE::hash_map additional_map_t ; #endif #endif #if !defined(RTOS_THREADX) && !defined(BESTA_OS) && !defined NSPIRE // #define WITH_INVA #if defined(__APPLE__) || defined(x86_64) #define LP_TAB_SIZE 15 // slice size will be 2^LP_TAB_SIZE // #define LP_SMALL_PRIMES #define LP_TAB_TOGETHER #define USE_MORE_PRIMES #else #define LP_TAB_SIZE 15 // slice size will be 2^LP_TAB_SIZE #endif // APPLE or 64 bits #endif // !defined RTOS_THREADX and BESTA_OS #ifdef LP_TAB_SIZE #define LP_MASK ((1< lp_tab_t; #endif #ifdef LP_TAB_SIZE #define LP_BIT_LIMIT 15 #else #define LP_BIT_LIMIT 15 #endif #if GIAC_ADDITIONAL_PRIMES==16 typedef unsigned short additional_t; #else typedef int additional_t; #endif inline int _equalposcomp(const std::vector & v, additional_t w){ int n=1; for (std::vector::const_iterator it=v.begin(),itend=v.end();it!=itend;++it){ if ((*it)==w) return n; else n++; } return 0; } // #define SQRTMOD_OUTSIDE #define WITH_LOGP // if defined primes should not exceed 2^24 (perhaps 2^25, choice of sqrt) struct small_basis_t { unsigned short root1; unsigned short root2; unsigned short p; unsigned short logp; }; #ifdef SQRTMOD_OUTSIDE struct basis_t { unsigned root1; // first root position in slice unsigned root2; // second root position ushort_t p:24; // the prime p #ifdef WITH_LOGP unsigned char logp:8; // could be unsigned char #endif basis_t():root1(0),root2(0),p(2) { #ifdef WITH_LOGP logp=sizeinbase2(p); #endif } basis_t(ushort_t _p):root1(0),root2(0),p(_p) { #ifdef WITH_LOGP logp=sizeinbase2(p); #endif } } ; #else // SQRTMOD_OUTSIDE struct basis_t { unsigned root1; // first root position in slice unsigned root2; // second root position ushort_t p; // the prime p unsigned sqrtmod:24; #ifdef WITH_LOGP unsigned char logp:8; // could be unsigned char #endif basis_t():root1(0),root2(0),p(2),sqrtmod(0) { #ifdef WITH_LOGP logp=sizeinbase2(p); #endif } basis_t(ushort_t _p):root1(0),root2(0),p(_p),sqrtmod(0) { #ifdef WITH_LOGP logp=sizeinbase2(p); #endif } basis_t(ushort_t _p,ushort_t _sqrtmod):root1(0),root2(0),p(_p),sqrtmod(_sqrtmod) { #ifdef WITH_LOGP logp=sizeinbase2(p); #endif } } ; #endif // SQRTMOD_OUTSIDE #ifdef LP_SMALL_PRIMES static inline void core_sieve(slicetype * slice,small_basis_t * bit,small_basis_t * bitend) { for (;bit!=bitend;++bit){ // first root is at bit->root1 register unsigned p=bit->p; register unsigned char nbits=bit->logp; register unsigned pos=bit->root1,pos2=bit->root2; if (pos==pos2){ for (;pos<32768; pos += p){ slice[pos] -= nbits; } bit->root2=bit->root1 = pos-32768; // save for next slice } else { for (;pos<32768; pos += p){ slice[pos] -= nbits; } bit->root1 = pos-32768; // save for next slice // second root, polynomial has 2 distinct roots for (;pos2<32768;pos2 += p){ slice[pos2] -= nbits; } bit->root2 = pos2-32768; } } } #else // LP_SMALL_PRIMES #ifdef LP_TAB_SIZE #define SLICEEND (1<p); // int next=1 << nbits; for (;bit!=bitend;++bit){ // first root is at bit->root1 register ushort_t p=bit->p; #ifdef WITH_LOGP nbits=bit->logp; #else if (p>next){ ++nbits; #if !defined(BESTA_OS) && !defined(RTOS_THREADX) && !defined NSPIRE if (nbits==LP_BIT_LIMIT+1) break; #endif next *=2; } #endif register unsigned pos=bit->root1,pos2=bit->root2; if (pos==pos2){ for (;int(pos)root2=bit->root1 = pos-SLICEEND; // save for next slice } else { for (;int(pos)root1 = pos-SLICEEND; // save for next slice // second root, polynomial has 2 distinct roots for (;int(pos2)root2 = pos2-SLICEEND; } } #if !defined(RTOS_THREADX) && !defined(BESTA_OS) && !defined NSPIRE #ifndef LP_TAB_SIZE for (;bit!=bitend;++bit){ // same as above but we are sieving with primes >2^15, no need to check for nbits increase register ushort_t p=bit->p; register unsigned pos=bit->root1; for (;posroot1 = pos-ss; // save for next slice // if (sameroot) continue; pos=bit->root2; for (;posroot2 = pos-ss; } #endif #endif return bit; } #endif // LP_SMALL_PRIMES // sieve in [sqrtN+shift,sqrtN+shift+slice.size()-1] // return -1 if memory problem, or the number of relations int msieve(const gen & a,const vecteur & sqrtavals, const vecteur &bvals,const mpz_t& c, vector & basis,unsigned lp_basis_pos, #ifdef LP_SMALL_PRIMES vector & small_basis, #endif unsigned maxadditional, #ifdef ADDITIONAL_PRIMES_HASHMAP additional_map_t & additional_primes_map, #else vector & additional_primes,vector & additional_primes_twice, #endif const gen & N,const gen & isqrtN, slicetype * slice,int ss,int shift, ushort_t * puissancesbegin,ushort_t* & puissancesptr,ushort_t * puissancesend, vector & curpuissances,vector &recheck, vector & axbmodn, mpz_t & z1,mpz_t & z2,mpz_t & z3,mpz_t & alloc1,mpz_t & alloc2,mpz_t & alloc3,mpz_t & alloc4,mpz_t & alloc5, #ifdef LP_TAB_SIZE const lp_tab_t & lp_tab, #endif GIAC_CONTEXT){ int nrelations=0; // first fill slice with expected number of bits of // (isqrtN+shift)^2-N = 2*shift*isqrtN + negl. // -> log(2*isqrtN)+log(shift) int shiftss=absint(shift+ss),absshift=absint(shift); int nbits=mpz_sizeinbase(*isqrtN._ZINTptr,2)+sizeinbase2(absshift>shiftss?absshift:shiftss); // int nbits1=int(0.5+std::log(evalf_double(isqrtN,1,context0)._DOUBLE_val/2.*(absshift>shiftss?absshift:shiftss))/std::log(2.)); // int curbits=0; int bs=int(basis.size()); double up_to=1.5; if (nbits>70) up_to += (0.8*(nbits-70))/70; if (debug_infolevel>7) *logptr(contextptr) << CLOCK() << gettext("Sieve tolerance factor ") << up_to << endl; unsigned char logB=(unsigned char) (nbits-int(up_to*sizeinbase2(basis.back().p)+.5)); // unsigned char logB=(unsigned char) (nbits-int(up_to*std::log(double(basis.back().p))/std::log(2.0)+.5)); if (debug_infolevel>6) *logptr(contextptr) << CLOCK() << gettext(" reset") << endl; // assumes slice type is size 1 byte and multiple of 32 #ifdef x86_64 ulonglong * ptr=(ulonglong *) &slice[0]; ulonglong * ptrend=ptr+ss/8; ulonglong pattern=(logB <<24)|(logB<<16)|(logB<<8) | logB; pattern = (pattern << 32) | pattern; for (;ptr!=ptrend;++ptr){ *ptr=pattern; } #else unsigned * ptr=(unsigned *) &slice[0]; unsigned * ptrend=ptr+ss/4; unsigned pattern=(logB <<24)|(logB<<16)|(logB<<8) | logB; for (;ptr!=ptrend;++ptr){ *ptr=pattern; } #endif if (debug_infolevel>8) *logptr(contextptr) << CLOCK() << gettext(" end reset, nbits ") << nbits << endl; // now for all primes p in basis move in slice from p to p // decrease slice[] by number of bits in p // determines the first prime used in basis #if 0 // def WITH_LOGP nbits=2*mpz_sizeinbase(*isqrtN._ZINTptr,2); int next=50; // note that msieve leaves 20 to 22 primes for normal range, and 15 for large nbits = sizeinbase2(next); #else if (nbits>120) nbits = 7; else { if (nbits>90) nbits = 6; else { if (nbits>78) nbits=5; else nbits = 4; } } int next = 1 << (nbits-1); #endif unsigned bstart; for (bstart=0;bstartnext){ if (debug_infolevel>7) *logptr(contextptr) << gettext("Sieve first prime ") << p << " nbits " << nbits << endl; break; } #ifdef LP_SMALL_PRIMES int pos=small_basis[bstart].root1; pos=(pos-ss)%p; if (pos<0) pos+=p; small_basis[bstart].root1=pos; pos=small_basis[bstart].root2; pos=(pos-ss)%p; if (pos<0) pos+=p; small_basis[bstart].root2=pos; #else // update pos_root_mod for later check int pos=basis[bstart].root1; pos=(pos-ss)%p; if (pos<0) pos+=p; basis[bstart].root1=pos; pos=basis[bstart].root2; pos=(pos-ss)%p; if (pos<0) pos+=p; basis[bstart].root2=pos; #endif } next *= 2; if (debug_infolevel>8) *logptr(contextptr) << CLOCK() << gettext(" sieve begin ") << endl; // bool sameroot; // Should be there to avoid counting twice the same root but it's faster to ignore it..; #ifdef LP_SMALL_PRIMES small_basis_t * bit=&small_basis[bstart], * bitend=&small_basis[0]+small_basis.size(); core_sieve(slice,bit,bitend); #else basis_t * bit=&basis[bstart], * bitend=&basis[0]+bs; #ifdef LP_TAB_SIZE bitend=core_sieve(slice,ss,bit,&basis[0]+lp_basis_pos); #else bitend=core_sieve(slice,ss,bit,bitend); #endif #endif slicetype * st=slice, * stend=slice+ss; #ifdef LP_TAB_SIZE // sieve for large prime using saved position if (!lp_tab.empty()){ const lp_entry_t * lpit=&lp_tab[0],*lpitend=lpit+lp_tab.size(),*lpitend1=lpitend-8; if (lpitend-lpit>8){ for (;lpitpos] -= 16; slice[lpit[1].pos] -= 16; slice[lpit[2].pos] -= 16; slice[lpit[3].pos] -= 16; slice[lpit[4].pos] -= 16; slice[lpit[5].pos] -= 16; slice[lpit[6].pos] -= 16; slice[lpit[7].pos] -= 16; } } for (;lpitpos] -= 16; } #endif unsigned cl=0; if (debug_infolevel>6) cl=CLOCK(); if (debug_infolevel>8) *logptr(contextptr) << cl << gettext("relations ") << endl; // now find relations st=slice; stend=slice+ss; #ifdef x86_64 ulonglong * st8=(ulonglong *) &slice[0],*st8end=st8+ss/8; #else unsigned * st4=(unsigned *) &slice[0],*st4end=st4+ss/4; #endif for ( #ifdef x86_64 ;st8!=st8end;st8+=4 #else ;st4 posss int posss=ss-pos; // always positive for (;basisptr!=basisend;++basisptr){ register int bi=basisptr->p; // check if we have a root register int check=bi-(posss%bi); if (check!=bi && check!=int(basisptr->root1) && check!=int(basisptr->root2)) continue; if (check==bi && basisptr->root1 && basisptr->root2) continue; recheck.push_back(bi); } // end for on (small) primes #ifdef LP_TAB_SIZE // add primes from large prime hashtable lp_tab_t::const_iterator lpit=lp_tab.begin(),lpend=lp_tab.end(); int hash_pos=recheck.size(); for (;lpit!=lpend;++lpit){ if (pos==int(lpit->pos)){ recheck.push_back(lpit->p); } } if (int(recheck.size())>hash_pos+1) sort(recheck.begin(),recheck.end()); #endif // now divide first by product of elements of recheck double prod=1,nextprod=1; for (unsigned k=0;k255){ curpuissances.push_back(0); done=true; } if (done){ for (;j;--j) curpuissances.push_back(bi); } else { for (;j>=256;j-=256) curpuissances.push_back(bi<<8); if (j) curpuissances.push_back( (bi << 8) | j); } } if (small_) mpz_set_si(z1,Z1); if (mpz_cmp_si(z1,1)==0){ // is_one(tmp)){ ++nrelations; if (debug_infolevel>6) *logptr(contextptr) << CLOCK() << gettext(" true relation ") << endl; axbmodn.push_back(axbinv(int(sqrtavals.size())-1,shiftpos,int(bvals.size())-1,int(puissancesptr-puissancesbegin),int(puissancesptr-puissancesbegin)+int(curpuissances.size()))); for (unsigned i=0;i=puissancesend) return -1; *puissancesptr=curpuissances[i]; } } else { unsigned param2; #if (GIAC_ADDITIONAL_PRIMES==16) param2=0xffff; #else param2=maxadditional; #endif if (mpz_cmp_ui(z1,param2)>0){ if (debug_infolevel>6) *logptr(contextptr) << gen(z1) << gettext(" Sieve large remainder:") << endl; } else { #ifdef GIAC_ADDITIONAL_PRIMES additional_t P=mpz_get_ui(z1); // if (int(P)>2*int(basis.back())) continue; // if (debug_infolevel>5) if (debug_infolevel>6) *logptr(contextptr) << CLOCK() << " " << P << " remain " << endl; #ifdef ADDITIONAL_PRIMES_HASHMAP // add relation ++nrelations; curpuissances.push_back(1); // marker #if (GIAC_ADDITIONAL_PRIMES==32) #ifndef PRIMES32 curpuissances.push_back(P >> 16); #endif #endif curpuissances.push_back(P); for (unsigned i=0;i=puissancesend) return -1; *puissancesptr=curpuissances[i]; } additional_map_t::iterator it=additional_primes_map.find(P),itend=additional_primes_map.end(); if (it!=itend) // build a large prime relation (P is the large prime) axbmodn.push_back(axbinv(sqrtavals.size()-1,shiftpos,bvals.size()-1,(puissancesptr-puissancesbegin)-curpuissances.size(),(puissancesptr-puissancesbegin))); else // record a partial relation additional_primes_map[P]=axbinv(sqrtavals.size()-1,shiftpos,bvals.size()-1,(puissancesptr-puissancesbegin)-curpuissances.size(),(puissancesptr-puissancesbegin)); #else int Ppos=_equalposcomp(additional_primes,P); // this is in O(additional^2)=o(B^3) if (Ppos){ if (debug_infolevel>6) *logptr(contextptr) << P << gettext(" already additional") << endl; --Ppos; additional_primes_twice[Ppos]=true; } else { // add a prime in additional_primes if <=QS_B_BOUND if (int(additional_primes.size())>=4*bs #if defined(RTOS_THREADX) || defined(BESTA_OS) || defined NSPIRE || bs+additional_primes.size()>700 #endif ) continue; additional_primes.push_back(P); additional_primes_twice.push_back(false); Ppos=int(additional_primes.size())-1; } // add relation curpuissances.push_back(1); // marker #if GIAC_ADDITIONAL_PRIMES==32 #ifndef PRIMES32 curpuissances.push_back(P >> 16); #endif #endif curpuissances.push_back(P); axbmodn.push_back(axbinv(int(sqrtavals.size())-1,shiftpos,int(bvals.size())-1,int(puissancesptr-puissancesbegin),int(puissancesptr-puissancesbegin)+int(curpuissances.size()))); for (unsigned i=0;i=puissancesend) return -1; *puissancesptr=curpuissances[i]; } #endif // ADDITIONAL_PRIMES_HASHMAP #endif // GIAC_ADDITIONAL_PRIMES } } } } // end for loop on slice array if (debug_infolevel>6){ unsigned cl2=CLOCK(); *logptr(contextptr) << cl2 << gettext(" end relations ") << cl2-cl << endl; } return nrelations; } // #define MP_MODINV_1 #ifdef MP_MODINV_1 static inline unsigned mp_modinv_1(unsigned a, unsigned p) { unsigned ps1, ps2, dividend, divisor, rem, q, t; unsigned parity; q = 1; rem = a; dividend = p; divisor = a; ps1 = 1; ps2 = 0; parity = 0; while (divisor > 1) { rem = dividend - divisor; t = rem - divisor; if (rem >= divisor) { q += ps1; rem = t; t -= divisor; if (rem >= divisor) { q += ps1; rem = t; t -= divisor; if (rem >= divisor) { q += ps1; rem = t; t -= divisor; if (rem >= divisor) { q += ps1; rem = t; t -= divisor; if (rem >= divisor) { q += ps1; rem = t; t -= divisor; if (rem >= divisor) { q += ps1; rem = t; t -= divisor; if (rem >= divisor) { q += ps1; rem = t; t -= divisor; if (rem >= divisor) { q += ps1; rem = t; if (rem >= divisor) { q = dividend / divisor; rem = dividend % divisor; q *= ps1; } } } } } } } } } q += ps2; parity = ~parity; dividend = divisor; divisor = rem; ps2 = ps1; ps1 = q; } if (parity == 0) return ps1; else return p - ps1; } #endif #if (defined __i386__ || defined __x86_64__) && !defined PIC && !defined _I386_ && !defined __APPLE__ && !defined VISUALC && !defined(FIR_LINUX) && !defined(FIR_ANDROID) #define _I386_ #endif #ifdef _I386_ // a->a+b*c mod m inline void addmultmod(int & a,int b,int c,int m){ asm volatile("testl %%ebx,%%ebx\n\t" /* sign bit=1 if negative */ "jns .Lok%=\n\t" "addl %%edi,%%ebx\n" /* a+=m*/ ".Lok%=:\t" "imull %%ecx; \n\t" /* b*c in edx:eax */ "addl %%ebx,%%eax; \n\t" /* b*c+a */ "adcl $0x0,%%edx; \n\t" /* b*c+a carry */ "idivl %%edi; \n\t" :"=d"(a) :"a"(b),"b"(a),"c"(c),"D"(m) ); } #endif inline int modmult(int a,int b,unsigned p){ #ifdef _I386_ register int res; asm volatile("imull %%edx\n\t" /* a*b-> edx:eax */ "idivl %%ecx\n\t" /* edx:eax div p -> quotient=eax, remainder=edx */ :"=d"(res) :"a"(a),"d"(b),"c"(p) : ); return res; #else return a*longlong(b) % p; #endif } // assumes b>0 and |a|0 so that all remainders below are >=0 a+=b; #ifdef _I386_ // works only for ushort_t == unsigned short // int res=mp_modinv_1(a,b),p=b; /* GDB: si will step in assembly, info registers show register content, x/i $pc show next ins */ asm volatile("movl $0,%%edi\n\t" "movl $1,%%ecx\n\t" "movl $0,%%edx\n\t" ".Lloop%=:\t" "movl %%esi,%%eax\n\t" "andl $0x80000000,%%esi\n\t" "xorl $0x80000000,%%esi\n\t" /* parity indicator for sign */ "andl $0x7fffffff,%%eax\n\t" /* clear high bit of ax */ "divl %%ebx\n\t" /* divide si by bx, ax=quotient, dx=rem */ "orl %%ebx,%%esi\n\t" /* copy bx in si but keep high bit of si */ "movl %%edx,%%ebx\n\t" /* si now contains bx and bx the remainder */ "mull %%ecx\n\t" /* quotient*cx is in ax (dx=0) */ "addl %%eax,%%edi\n\t" /* di <- di+q*cx*/ "xchgl %%edi,%%ecx\n\t" /* cx <- origi di+q*cx, di <- orig cx */ "testl %%ebx,%%ebx\n\t" "jne .Lloop%=\n\t" :"=D"(a),"=S"(b) :"S"(b),"b"(a) :"%eax","%ecx","%edx" ); if (b<0) b=b&0x7fffffff; else a=-a; a=(b==1)?a:0; // if ((a-res)%p) // CERR << "error" << endl; return a; #else // i386 #ifdef MP_MODINV_1 return mp_modinv_1(a,b); #endif // r0=b=ab*a+1*b // r1=a=aa*a+0*b int aa(1),ab(0),ar(0); #if 0 ushort_t q,r; while (a){ q=b/a; ar=ab-q*aa; r=b-q*a; if (!r) return a==1?aa:0; q=a/r; ab=aa-q*ar; b=a-q*r; if (!b) return r==1?ar:0; q=r/b; aa=ar-q*ab; a=r-q*b; } return b==1?ab:0; #else div_t qr; while (a){ qr=div(b,a); ar=ab-qr.quot*aa; b=a; a=qr.rem; ab=aa; aa=ar; } if (b==1) return ab; return 0; #endif #endif // i386 } #if 0 // def PRIMES32 // assumes |a|0 so that all remainders below are >=0 a+=b; // r0=b=ab*a+1*b // r1=a=aa*a+0*b longlong aa(1),ab(0),ar(0); longlong q,r; lldiv_t qr; while (a){ qr=lldiv(b,a); ar=ab-qr.quot*aa; b=a; a=qr.rem; ab=aa; aa=ar; } if (b==1) return ab; return 0; } #endif static int find_multiplier(const gen & n,double & delta,GIAC_CONTEXT){ delta=0; if (n.type!=_ZINT) return 1; static const unsigned char mult[] = { 1, 3, 5, 7, 11, 13, 15, 17, 19, 21, 23, 29, 31, 33, 35, 37, 39, 41, 43, 47}; // only odd values for multiplier unsigned nmult=sizeof(mult)/sizeof(unsigned char); double scores[50]; int nmodp=modulo(*n._ZINTptr,8),knmodp; // init scores and set value for 2 double ln2=std::log(2.0); for (unsigned i=0;i6){ for (unsigned i=0;i relations,unsigned j,ushort_t * curpui,ushort_t * curpuiend,const vector & basis,const vector & additional_primes){ unsigned curpuisize=unsigned(curpuiend-curpui); bool done=false; unsigned i=0; // position in basis unsigned k=0; // position in curpui additional_t p=0; // prime unsigned bs=unsigned(basis.size()); for (;k>= 8; } else { int c=1; for (;k+1 & p,vector & add_p,const gen & N,const vector & basis,const vector & additional_primes,const vecteur & sqrtavals,const vecteur & bvals,ushort_t * puissancestab,mpz_t & zq,mpz_t & zr,mpz_t & alloc1, mpz_t & alloc2,mpz_t & alloc3,mpz_t & alloc4, mpz_t & alloc5){ // x=x*(a*shiftpos+b), y =y*sqrta; mpz_set_si(alloc2,A.shiftpos); if (sqrtavals[A.aindex].type==_INT_){ mpz_mul_ui(alloc1,alloc2,sqrtavals[A.aindex].val); mpz_mul_ui(alloc2,alloc1,sqrtavals[A.aindex].val); mpz_mul_ui(zy,zy,sqrtavals[A.aindex].val); } else { mpz_mul(alloc1,alloc2,*sqrtavals[A.aindex]._ZINTptr); mpz_mul(alloc2,alloc1,*sqrtavals[A.aindex]._ZINTptr); mpz_mul(zy,zy,*sqrtavals[A.aindex]._ZINTptr); } mpz_add(alloc1,alloc2,*bvals[A.bindex]._ZINTptr); // mpz_mul(alloc2,alloc1,*invsqrtamodnvals[A.aindex]._ZINTptr); mpz_mul(zr,zx,alloc1); #ifdef USE_GMP_REPLACEMENTS mp_grow(&alloc1,zr.used+2); mpz_set_ui(alloc1,0); alloc1.used = zr.used +2 ; mpz_set(alloc2,zr); mpz_set(alloc3,*N._ZINTptr); // mpz_set_si(alloc4,0); // mpz_set_si(alloc5,0); alloc_mp_div(&zr,N._ZINTptr,&zq,&zx,&alloc1,&alloc2,&alloc3,&alloc4,&alloc5); mp_grow(&alloc1,zy.used+2); mpz_set_ui(alloc1,0); alloc1.used = zy.used +2 ; mpz_set(alloc2,zy); mpz_set(alloc3,*N._ZINTptr); // mpz_set_si(alloc4,0); // mpz_set_si(alloc5,0); alloc_mp_div(&zy,N._ZINTptr,&zq,&zy,&alloc1,&alloc2,&alloc3,&alloc4,&alloc5); #else mpz_tdiv_r(zx,zr,*N._ZINTptr); mpz_tdiv_r(zy,zy,*N._ZINTptr); #endif bool done=false; unsigned bi=0; ushort_t * it=puissancestab+A.first,* itend=puissancestab+A.second; for (;it!=itend;++it){ if (*it==0xffff) continue; if (*it==1){ ++it; additional_t p=*it; #if GIAC_ADDITIONAL_PRIMES==32 #ifndef PRIMES32 p <<= 16; ++it; p += *it; #endif #endif int pos=_equalposcomp(additional_primes,p); if (pos) ++add_p[pos-1]; else { // otherwise ERROR!!! } break; } if (!*it){ done=true; continue; } if (done){ while (bi>8)) ++bi; p[bi]+=(*it&0xff); } } } void find_bv_be(int tmp,int & bv,int &be){ bv=1; be=-1; while (tmp%2==0){ ++bv; tmp /= 2; } tmp /= 2; if (tmp%2) be=1; else be=-1; } #ifdef PRIMES32 // Change b coeff of polynomial: update roots for small primes // for large primes do it depending on LP_TAB_TOGETHER #ifdef LP_SMALL_PRIMES void copy(vector & basis,vector & small_basis){ small_basis_t * small_basisptr=&small_basis[0], * small_basisend=small_basisptr+small_basis.size(); basis_t * basisptr=&basis[0]; unsigned next=2,logp=1; if (small_basis[0].p==0){ for (;small_basisptrroot1=basisptr->root1; small_basisptr->root2=basisptr->root2; register unsigned short p =basisptr->p; small_basisptr->p = p; small_basisptr->logp=logp; if (p>next){ ++logp; next *= 2; } } } else { for (;small_basisptrroot1=basisptr->root1; small_basisptr->root2=basisptr->root2; } } } void switch_roots(const vector & bainv2,vector & basis,vector & small_basis,unsigned lp_basis_pos,unsigned nslices,unsigned slicesize,unsigned bv,int be,int afact,const vector & pos,gen b,mpz_t & zq,int M){ unsigned bs=basis.size(); const int * bvpos=&bainv2[(bv-1)*bs]; #ifdef LP_TAB_TOGETHER const int * bvposend=bvpos+lp_basis_pos; #else const int * bvposend=bvpos+bs; #endif basis_t * basisptr=&basis[0]; if (be>0){ for (;bvposp; register int r=basisptr->root1-(*bvpos); if (r<0) r+=p; basisptr->root1=r; r=basisptr->root2-(*bvpos); if (r<0) r+=p; basisptr->root2=r; } } else { for (;bvposp; register int r=basisptr->root1+(*bvpos); if (r>p) r-=p; basisptr->root1=r; r=basisptr->root2+(*bvpos); if (r>p) r-=p; basisptr->root2=r; } } // adjust sieve position for prime factors of a, for (int j=0;j & bainv2,vector & basis,unsigned lp_basis_pos,unsigned nslices,unsigned slicesize,unsigned bv,int be,int afact,const vector & pos,gen b,mpz_t & zq,int M){ unsigned bs=basis.size(); #ifdef LP_TAB_SIZE const int * bvpos=&bainv2[(bv-1)*bs],* bvposend=bvpos+lp_basis_pos; #else const int * bvpos=&bainv2[(bv-1)*bs],* bvposend=bvpos+bs; #endif basis_t * basisptr=&basis[0]; unsigned decal0=nslices*slicesize; if (decal0>=basis.back().p){ if (be<0){ for (;bvposp; register unsigned decal = (decal0+(*bvpos))% p; register unsigned r=basisptr->root1+decal; if (r>p) r -= p; basisptr->root1 = r; r = basisptr->root2+decal; if (r>p) r -= p; basisptr->root2 = r; } } else { for (;bvposp; register unsigned decal = (decal0-(*bvpos))% p; register unsigned r=basisptr->root1+decal; if (r>p) r -= p; basisptr->root1 = r; r = basisptr->root2+decal; if (r>p) r -= p; basisptr->root2 = r; } } } else { // should not be reached since Mtarget is about basis.back() for (;bvposp; register unsigned decal = (decal0+p-be*(*bvpos))% p; register unsigned r=basisptr->root1+decal; if (r>p) r -= p; basisptr->root1 = r; r = basisptr->root2+decal; if (r>p) r -= p; basisptr->root2 = r; } } // adjust sieve position for prime factors of a, for (int j=0;j0){ for (;bvposp; register int r=basisptr->root1-(*bvpos); if (r<0) r+=p; basisptr->root1=r; r=basisptr->root2-(*bvpos); if (r<0) r+=p; basisptr->root2=r; } } else { for (;bvposp; register int r=basisptr->root1+(*bvpos); if (r>int(p)) r-=p; basisptr->root1=r; r=basisptr->root2+(*bvpos); if (r>int(p)) r-=p; basisptr->root2=r; } } #endif } #endif // LP_SMALL_PRIMES #endif // PRIMES32 // Change a, the leading coeff of polynomial: initialize all roots (small and large primes) void init_roots(vector & basis, #ifdef LP_SMALL_PRIMES vector & small_basis, #endif #ifdef WITH_INVA vector & Inva, #endif #ifdef SQRTMOD_OUTSIDE const vector & sqrtmod, #endif #ifdef PRIMES32 vector & bainv2,int afact,int afact0, #else ulonglong usqrta, #endif const gen & a,const gen & b,const vecteur & bvalues,mpz_t & zq,unsigned M){ unsigned bs=unsigned(basis.size()); basis_t * basisptr=&basis.front(),*basisend=basisptr+bs; #ifdef SQRTMOD_OUTSIDE vector::const_iterator sqrtmodit=sqrtmod.begin(); #endif for (int i=0;basisptr!=basisend;++i,++basisptr){ ushort_t p=basisptr->p; // find inverse of a mod p #ifdef PRIMES32 int j=invmodnoerr(modulo(*a._ZINTptr,p),p); // deltar[i]=((2*ulonglong(basis[i].sqrtmod))*j)%p; #else // PRIMES32 unsigned modu=usqrta%p; modu=(modu*modu)%p; int j=invmodnoerr(modu,p); #endif // PRIMES32 if (j<0) j += p; unsigned inva=j; #ifdef WITH_INVA Inva[i]=inva; #else #ifdef PRIMES32 // set roots change values for all b coeffs for this a if (afact>afact0){ int * ptr=&bainv2[i]; for (int j=1;jsqrtmod; #endif int bmodp=p-modulo(*b._ZINTptr,p); if (inva){ if (p<=37000){ // sqrtm<=p/2, bmodproot1=(M+(bmodp+sqrtm)*inva) % p; basisptr->root2=(M+(bmodp+p-sqrtm)*inva) % p; continue; } #ifdef _I386_ register int q=M; addmultmod(q,bmodp+sqrtm,inva,p); basisptr->root1=q; q=M; addmultmod(q,bmodp+p-sqrtm,inva,p); basisptr->root2=q; #else basisptr->root1=(M+longlong(bmodp+sqrtm)*inva) % p; basisptr->root2=(M+longlong(bmodp+p-sqrtm)*inva) % p; #endif continue; } int cmodp=modulo(zq,p); int q=(M+longlong(cmodp)*invmodnoerr((2*bmodp)%p,p))%p; if (q<0) q+=p; basisptr->root2=q; basisptr->root1=q; } #ifdef WITH_INVA #ifdef PRIMES32 if (afact>afact0){ int * bainv2ptr=&bainv2.front(); basis_t * basisptr,*basisend=&basis.front()+bs; for (int j=1;j::const_iterator invait=Inva.begin(); for (basisptr=&basis.front();basisptrp; if (r<0) r += basisptr->p; *bainv2ptr=r; } } else { // longlong up1=up1tmp[2*j]; // longlong tmp=up1tmp[2*j+1]; // tmp is <= P^2 where P is the largest factor of a mpz_t & bz=*bvalues[j]._ZINTptr; vector::const_iterator invait=Inva.begin(); for (basisptr=&basis.front();basisptrp; *bainv2ptr=((modulo(bz,p))*longlong(2*(*invait))) % p; } } } } #endif // PRIMES32 #endif // WITH_INVA #ifdef LP_SMALL_PRIMES // copy primes<2^16 into small_basis copy(basis,small_basis); #endif } // find relations using (a*x+b)^2=a*(a*x^2+b*x+c) mod n where // we sieve on [-M,M] for as many polynomials as required // a is a square, approx sqrt(2*n)/M, and n is a square modulo all primes dividing a // b satisifies b^2=n mod a (b in [0,a[) // c=(n-b^2)/a bool msieve(const gen & n_orig,gen & pn,GIAC_CONTEXT){ if (n_orig.type!=_ZINT) return false; // find multiplier double delta; int multiplier=find_multiplier(n_orig,delta,contextptr); gen N(multiplier*n_orig); double Nd=evalf_double(N,1,contextptr)._DOUBLE_val; #if defined RTOS_THREADX || defined NSPIRE if (Nd>1e40) return false; #endif #ifdef BESTA_OS if (Nd>1e40) return false; #endif #ifdef PRIMES32 if (Nd>1e76) return false; #else if (Nd>1e63) return false; #endif int Ndl=int(std::log10(Nd)-std::log10(double(multiplier))+.5); // +2*delta); #ifdef LP_TAB_SIZE int slicesize=(1 << LP_TAB_SIZE); #else int slicesize=(QS_SIZE>=65536 && Ndl<61)?32768:QS_SIZE; #endif double B=std::exp(std::sqrt(2.0)/4*std::sqrt(std::log(Nd)*std::log(std::log(Nd))))*0.45; if (B<200) B=200; int pos1=70,pos0=23,afact=2,afixed=0; // pos position in the basis, afact number of factors // FIXME Will always include the 3 first primes of the basis // set a larger Mtarget gives less polynomials but also use less memory #if defined(RTOS_THREADX) || defined(RTOS_THREADX) || defined NSPIRE double Mtarget=0.95e5; if (Nd>1e36) Mtarget=1.2e5; #else double Mtarget=0.55e5; #ifndef USE_MORE_PRIMES // FIXME improve! in fact use more primes on Core, less on Opteron if (Ndl>=50){ Ndl-=50; short int Btab[]={ // 50 1900,2100,2300,2500,2700,2900,3100,3400,3700,4000, // 60 4300,4600,4900,5300,5700,6200,6800,7500,8300,9200, // 70 10000,11000,12000,13000,14000,15000,16000 }; if (Ndl7) Mtarget=0.95e5; if (Ndl>11) Mtarget=1.3e5; if (Ndl>15) Mtarget=1.6e5; if (Ndl>19) Mtarget=1.92e5; } #else if (Ndl>=50) Mtarget=0.85e5; if (Ndl>65) Mtarget=1.3e5; #endif #endif if (debug_infolevel) *logptr(contextptr) << " " << CLOCK() << gettext(" sieve on ") << N << endl << gettext("Number of primes ") << B << endl; // first compute the prime basis and sqrt(N) mod p, p in basis vector basis; basis.reserve(unsigned(B)); #ifdef SQRTMOD_OUTSIDE vector sqrtmod; sqrtmod.reserve(basis.capacity()); basis.push_back(2); sqrtmod.push_back(1); #else basis.push_back(basis_t(2,1)); // I assume that N is odd... hence has sqrt 1 mod 2 #endif N.uncoerce(); // vector N256; int i; mpz_t zx,zy,zq,zr; mpz_init(zx); mpz_init(zy); mpz_init(zq); mpz_init(zr); // fastsmod_prepare(N,zx,zy,zr,N256); for (i=1;i6 && (i%500==99)) *logptr(contextptr) << CLOCK() << gettext(" sieve current basis size ") << basis.size() << endl; #if 1 // def USE_GMP_REPLACEMENTS // int n=fastsmod_compute(N256,j); int n=modulo(*N._ZINTptr,j),s; #else int n=smod(N,j).val,s; #endif if (n<0) n+=j; if (n==0){ #ifdef SQRTMOD_OUTSIDE basis.push_back(j); sqrtmod.push_back(0); #else basis.push_back(basis_t(j,0)); #endif } else { if (powmod(n,(unsigned long)((j-1)/2),(int)j)==1){ s=sqrt_mod(n,int(j),true,contextptr).val; if (s<0) s+=j; #ifdef SQRTMOD_OUTSIDE basis.push_back(j); sqrtmod.push_back(s); #else basis.push_back(basis_t(j,s)); #endif } } if (basis.size()>=B) break; } vector crible; int jp=0; if (basis.size() 2^16 in the basis for (;basis.size()65535){ break; } #endif if (debug_infolevel>6 && (i%500==99)) *logptr(contextptr) << CLOCK() << gettext(" sieve current basis size ") << basis.size() << endl; #if 1 // def USE_GMP_REPLACEMENTS // int n=fastsmod_compute(N256,jp); int n=modulo(*N._ZINTptr,jp),s; #else int n=smod(N,jp).val,s; #endif if (n<0) n+=jp; if (powmod(n,(unsigned long)((jp-1)/2),jp)==1){ s=sqrt_mod(n,jp,true,contextptr).val; if (s<0) s += jp; #ifdef LP_TAB_SIZE if (!lp_basis_pos && jp> (1< small_basis(lp_basis_pos); // will be filled by primes<2^16 #endif #ifdef TIMEOUT control_c(); #endif if (ctrl_c || interrupted){ mpz_clear(zx); mpz_clear(zy); mpz_clear(zq); mpz_clear(zr); return false; } double dtarget=1.1; if (Mtarget>16))*basis.back().p*ps; #else unsigned maxadditional=3*basis.back().p*ps; #endif if (debug_infolevel) *logptr(contextptr) << CLOCK() << gettext(" sieve basis OK, size ") << basis.size() << " largest prime in basis " << basis.back().p << " large prime " << maxadditional << " Mtarget " << Mtarget << endl ; int bs=int(basis.size()); gen isqrtN=isqrt(N); isqrtN.uncoerce(); // now compare isqrtN to a^2 for a in the basis double seuil=1.414*evalf_double(isqrtN,1,contextptr)._DOUBLE_val/Mtarget; // should be a seuil=std::sqrt(seuil); // should be product of primes of the basis #ifdef OLD_AFACT double dfactors=std::log10(seuil)/3; // fixed primes are choosen at basis[pos0], variables are choosen around 2000 afact=int(dfactors+.5); if (afact<=1){ afact=1; int i=20; for (;i<3*bs/4;++i){ if (seuil=3*bs/4){ afact=2; for (;i<3*bs/4;++i){ if (seuil=3, if (dfactors>5.4){ dfactors -= 3; // 3 large primes afixed = dfactors/.8; // at least 3 fixed afact = 3 + afixed; } else { dfactors -= 2; // 2 large primes afixed = dfactors/.8; if (afixed==0) afixed=1; afact = 2 +afixed; } for (int i=0;iafact){ afixed=i; afact=i+ivariable; curseuil=seuiltest; } } } for (int i=0;i isqrtN256; // fastsmod_prepare(isqrtN,zx,zy,zr,isqrtN256); vector isqrtNmodp(bs); for (int i=0;i axbmodn; // contains (sqrta,b,x) vector additional_primes; #ifndef ADDITIONAL_PRIMES_HASHMAP vector additional_primes_twice; #endif #ifdef LP_TAB_SIZE vector lp_map(128); // at most 128 slices in a sieve #endif vecteur sqrtavals,bvals; #ifdef GIAC_ADDITIONAL_PRIMES #ifdef ADDITIONAL_PRIMES_HASHMAP #ifdef EMCC additional_map_t additional_primes_map; #else additional_map_t additional_primes_map(8*bs); #endif axbmodn.reserve(bs); #else #if defined(RTOS_THREADX) || defined(BESTA_OS) || defined NSPIRE additional_primes.reserve(bs); additional_primes_twice.reserve(bs); axbmodn.reserve(2*bs); #else additional_primes.reserve(4*bs); additional_primes_twice.reserve(4*bs); axbmodn.reserve(5*bs); #endif sqrtavals.reserve(bs/7); bvals.reserve(2*bs/7); #endif // ADDITIONAL_PRIMES_HASHMAP #else // GIAC_ADDITIONAL_PRIMES axbmodn.reserve(bs+1); #endif // now sieve unsigned todo_rel; unsigned marge=bs/100; if (marge<15) marge=15; mpz_t alloc1,alloc2,alloc3,alloc4,alloc5; mpz_init(alloc1); mpz_init(alloc2); mpz_init(alloc3); mpz_init(alloc4); mpz_init(alloc5); // vector a256,b256,tmpv; vector curpuissances,recheck,pos(afact); #ifdef WITH_INVA vector Inva(bs); #endif vecteur bvalues; // will contain values of b if afact<=afact0 or components of b if afact>afact0 // array for efficient polynomial switch (same a change b) when at least afact0 factors/a #ifdef PRIMES32 const int afact0=3; vector bainv2((afact-1)*bs); vector up1tmp; #endif for (int i=0;i1) end_pos1=pos1+100; if (avar>2) end_pos1=pos1+30; if (int(lp_basis_pos)=end_pos1 || basis[pos.back()].p>=45000){ int i=afact-2; for (;i>afixed;--i){ if (int(pos[i])=3, so that we can move pos[1] by thread while (Mval>1.1*Mtarget && int(pos[afixed-1])10){ // Mval is too small, decrease one factor of a --pos[0]; if (pos[0]<=10){ Mval=0; break; } double coeff=basis[pos[0]].p/double(basis[pos[0]+1].p); Mval=Mval/(coeff*coeff); } } if ( Mval <0.7*Mtarget ){ if (pos1>pos0+afixed+5 || Mval<32768){ // CERR << pos ; int i=afact-1; for (;i>afixed+1;--i){ if (pos[i]>pos[i-1]+5) break; } if (i<=afixed+1){ --pos1; for (i=0;i=todo_rel) break; int nrelationsa=0; // Not finished yet, construct a new value of a around ad=sqrt(2*n)/M // using a product of afact square of primes that are in the basis // and construct a vector of 2^(afact-1) corresponding values of b // and compute the values of inverses of a mod p ulonglong usqrta(basis[pos[0]].p); for (int i=1;i6) *logptr(contextptr) << CLOCK() << gettext(" initial value for M= ") << M << endl; int nslices=int(std::ceil((2.*M)/slicesize)); M=(nslices*slicesize)/2; bvalues.clear(); gen curprod=1; for (int i=0;;){ #ifdef SQRTMOD_OUTSIDE int s=sqrtmod[pos[i]]; #else int s=basis[pos[i]].sqrtmod; #endif int p=basis[pos[i]].p; longlong p2=p*longlong(p); // Hensel lift s to be a sqrt of n mod p^2: (s+p*r)^2=s^2+2p*r*s=n => r=(n-s^2)/p*inv(2*s mod p) int r=p<37000?int((modulo(*N._ZINTptr,p2)-s*s)/p):((smod(N,p2)-s*s)/p).val; r=(r*invmod(2*s,p))%p; // overflow should not happen because p is a factor of a hence choosen // in the 1000 range (perhaps up to 10 000, but not much larger) // if ((longlong(r)*p)!=r*p) CERR << "overflow" << endl; s += p*r; #ifdef PRIMES32 if (afact>afact0){ // store s*(inv( product(basis[pos[j]]^2,j!=i) mod p2)) in bvalues[i] longlong up1=(usqrta/p); longlong up=up1%p2; up=(up*up)%p2; //longlong tmp=(s*invmodnoerr(up,p2))%p2; //up1tmp.push_back(up1); //up1tmp.push_back(tmp); gen tmp=smod(s*invmod(gen(up),gen(p2)),p2); if (is_greater(0,tmp,contextptr)) tmp=-tmp; gen gup1(up1); bvalues.push_back(gup1*gup1*tmp); bvalues.back().uncoerce(); } else #endif { if (bvalues.empty()) bvalues.push_back(s); else { int js=int(bvalues.size()); for (int j=0;j6) *logptr(contextptr) << CLOCK() << gettext(" Computing inverses mod p of the basis ") << endl; // fastsmod_prepare(a,zx,zy,zr,a256); gen b; for (int i=0;i< (1<<(afact-1));++i){ #ifdef TIMEOUT control_c(); #endif if (ctrl_c || interrupted) break; #ifdef ADDITIONAL_PRIMES_HASHMAP todo_rel=bs+marge; #else todo_rel=bs+marge+unsigned(additional_primes.size()); #endif if (axbmodn.size()>=todo_rel) break; if (debug_infolevel>6) *logptr(contextptr) << CLOCK() << gettext(" Computing c ") << endl; #ifdef PRIMES32 int bv=1,be=-1; if (afact>afact0){ if (i==0){ b=0; for (unsigned j=0;j6) *logptr(contextptr) << CLOCK() << gettext(" Computing roots mod the basis ") << endl; // fastsmod_prepare(b,zx,zy,zr,b256); #ifdef PRIMES32 if (i && afact>afact0) switch_roots(bainv2,basis, #ifdef LP_SMALL_PRIMES small_basis, #endif lp_basis_pos,nslices,slicesize,bv,be,afact,pos,b,zq,M); else { init_roots(basis, #ifdef LP_SMALL_PRIMES small_basis, #endif #ifdef WITH_INVA Inva, #endif #ifdef SQRTMOD_OUTSIDE sqrtmod, #endif bainv2,afact,afact0, a,b,bvalues,zq,M); #ifdef LP_TAB_TOGETHER // init all hashtable for large primes at once unsigned cl; if (debug_infolevel>3){ cl=CLOCK(); *logptr(contextptr) << cl << gettext(" Init large prime hashtables ") << endl; } int total=(nslices << (afact-1)); if (int(lp_map.size()) < total) lp_map.resize(total); for (int k=0;k< total;++k) lp_map[k].clear(); if (lp_basis_pos){ for (int k=0;;){ basis_t * bit=&basis[lp_basis_pos], * bitend=&basis[0]+bs; unsigned endpos=nslices*slicesize; lp_tab_t * ptr=&lp_map[0]+k*nslices; for (;bit!=bitend;++bit){ register ushort_t p=bit->p; register unsigned pos=bit->root1; for (;pos> LP_TAB_SIZE))->push_back(lp_entry_t((pos & LP_MASK),p)); } pos=bit->root2; for (;pos> LP_TAB_SIZE))->push_back(lp_entry_t((pos & LP_MASK),p)); } } ++k; if (k== (1 << (afact-1))){ if (debug_infolevel>3){ unsigned cl2=CLOCK(); *logptr(contextptr) << cl2 << gettext(" End large prime hashtables ") << cl2-cl << endl; } break; } find_bv_be(k,bv,be); // switch roots to next polynomial int * bvpos=&bainv2[(bv-1)*bs],* bvposend=bvpos+bs; bvpos += lp_basis_pos; basis_t * basisptr=&basis[lp_basis_pos]; if (be>0){ for (;bvposp; register int r=basisptr->root1-(*bvpos); if (r<0) r+=p; basisptr->root1=r; r=basisptr->root2-(*bvpos); if (r<0) r+=p; basisptr->root2=r; } } else { for (;bvposp; register int r=basisptr->root1+(*bvpos); if (r>int(p)) r-=p; basisptr->root1=r; r=basisptr->root2+(*bvpos); if (r>int(p)) r-=p; basisptr->root2=r; } } } } #endif // LP_TAB_TOGETHER } // end else of if i==0 #if defined(LP_TAB_SIZE) && !defined(LP_TAB_TOGETHER) if (int(lp_map.size()) < nslices) lp_map.resize(nslices); for (int k=0;k< nslices;++k) lp_map[k].clear(); if (lp_basis_pos){ basis_t * bit=&basis[lp_basis_pos], * bitend=&basis[0]+bs; unsigned endpos=nslices*slicesize; for (;bit!=bitend;++bit){ register ushort_t p=bit->p; register unsigned pos=bit->root1; for (;pos> LP_TAB_SIZE].push_back(lp_entry_t((pos & LP_MASK),p)); } pos=bit->root2; for (;pos> LP_TAB_SIZE].push_back(lp_entry_t((pos & LP_MASK),p)); } } } #endif // LP_TAB_SIZE && !LP_TAB_TOGETHER #else // PRIMES32 init_roots(basis, #ifdef WITH_INVA Inva, #endif #ifdef SQRTMOD_OUTSIDE sqrtmod, #endif usqrta,a,b,bvalues,zq,M); #endif // PRIMES32 // we can now sieve in [-M,M[ by slice of size slicesize #ifndef GIAC_HAS_STO_38 if (debug_infolevel>5){ *logptr(contextptr) << CLOCK(); *logptr(contextptr) << gettext(" Polynomial a,b,M=") << a << "," << b << "," << M << " (" << pos << ")" ; *logptr(contextptr) << CLOCK() << endl; } #endif int nrelationsb=0; #ifdef LP_TAB_SIZE #endif for (int l=0;l=todo_rel) break; int shift=-M+l*slicesize; int slicerelations=msieve(a,sqrtavals, bvals,zq,basis,lp_basis_pos, #ifdef LP_SMALL_PRIMES small_basis, #endif maxadditional, #ifdef ADDITIONAL_PRIMES_HASHMAP additional_primes_map, #else additional_primes,additional_primes_twice, #endif N,isqrtN, slice,slicesize,shift,puissancestab,puissancesptr,puissancesend,curpuissances,recheck, axbmodn, zx,zy,zr,alloc1,alloc2,alloc3,alloc4,alloc5, #ifdef LP_TAB_SIZE #ifdef LP_TAB_TOGETHER lp_map[l+nslices*i], #else lp_map[l], #endif #endif contextptr); if (slicerelations==-1){ *logptr(contextptr) << gettext("Sieve error: Not enough memory ") << endl; break; } nrelationsb += slicerelations; #ifdef ADDITIONAL_PRIMES_HASHMAP todo_rel=bs+marge; #else todo_rel=bs+marge+unsigned(additional_primes.size()); #endif } if (nrelationsb==0) bvals.pop_back(); else nrelationsa += nrelationsb; } #if defined( RTOS_THREADX) || defined(BESTA_OS) || defined NSPIRE if (debug_infolevel){ #ifdef NSPIRE static int count_print=0; ++count_print; if (count_print%4==0) #endif *logptr(contextptr) << axbmodn.size() << " of " << todo_rel << " (" << 100-100*(todo_rel-axbmodn.size())/double(bs+marge) << "%)" << endl; } #endif if (nrelationsa==0){ sqrtavals.pop_back(); } #if !defined(RTOS_THREADX) && !defined(BESTA_OS) && !defined NSPIRE if (debug_infolevel>1) *logptr(contextptr) << CLOCK()<< gettext(" sieved : ") << axbmodn.size() << " of " << todo_rel << " (" << 100-100*(todo_rel-axbmodn.size())/double(bs+marge) << "%), M=" << M << endl; #endif } // end sieve loop if (debug_infolevel) *logptr(contextptr) << gettext("Polynomials a,b in use: #a ") << sqrtavals.size() << " and #b " << bvals.size() << endl; delete [] slice; #ifdef TIMEOUT control_c(); #endif if (ctrl_c || interrupted || puissancesptr==puissancesend){ mpz_clear(zx); mpz_clear(zy); mpz_clear(zq); mpz_clear(zr); mpz_clear(alloc1); mpz_clear(alloc2); mpz_clear(alloc3); mpz_clear(alloc4); mpz_clear(alloc5); delete [] puissancestab; return false; } // We have enough relations, make matrix, reduce it then find x^2=y^2 mod n congruences if (debug_infolevel) *logptr(contextptr) << CLOCK() << gettext(" sieve done: used ") << (puissancesptr-puissancestab)*0.002 << " K for storing relations (of " << puissancestablength*0.002 << ")" << endl; release_memory(isqrtNmodp); #ifdef GIAC_ADDITIONAL_PRIMES #ifdef ADDITIONAL_PRIMES_HASHMAP additional_primes.reserve(axbmodn.size()); vector::const_iterator it=axbmodn.begin(),itend=axbmodn.end(); for (;it!=itend;++it) { unsigned u=largep(*it,puissancestab); if (u) additional_primes.push_back(u); } sort(additional_primes.begin(),additional_primes.end()); // for binary search later #else if (debug_infolevel) *logptr(contextptr) << CLOCK() << gettext(" removing additional primes") << endl; // remove relations with additional primes which are used only once int lastp=int(axbmodn.size())-1,lasta=int(additional_primes.size())-1; for (int i=0;i<=lastp;++i){ ushort_t * curbeg=puissancestab+axbmodn[i].first, * curend=puissancestab+axbmodn[i].second; bool done=false; for (;curbeg!=curend;++curbeg){ if (*curbeg==1) break; } if (curbeg==curend) continue; ++curbeg; additional_t u=*curbeg; #if GIAC_ADDITIONAL_PRIMES==32 && !defined(PRIMES32) u <<=16 ; ++curbeg; u += *curbeg; #endif int pos=_equalposcomp(additional_primes,u); if (!pos) continue; if (pos>lasta){ // *logptr(contextptr) << cur << endl; continue; } --pos; if (additional_primes_twice[pos]) continue; axbmodn[i]=axbmodn[lastp]; --lastp; additional_primes[pos]=additional_primes[lasta]; additional_primes_twice[pos]=additional_primes_twice[lasta]; --lasta; --i; // recheck at current index } axbmodn.resize(lastp+1); additional_primes.resize(lasta+1); if (debug_infolevel) *logptr(contextptr) << CLOCK() << gettext(" end removing additional primes") << endl; #endif // ADDTIONAL_PRIMES_HASHMAP #endif // GIAC_ADDITIONAL_PRIMES // Make relations matrix (currently dense, FIXME improve to sparse and Lanczos algorithm) int C32=int(std::ceil(axbmodn.size()/32./GIAC_RREF_UNROLL))*GIAC_RREF_UNROLL; unsigned * tab=new unsigned[axbmodn.size()*C32],*tabend=tab+axbmodn.size()*C32; if (!tab){ mpz_clear(zx); mpz_clear(zy); mpz_clear(zq); mpz_clear(zr); mpz_clear(alloc1); mpz_clear(alloc2); mpz_clear(alloc3); mpz_clear(alloc4); mpz_clear(alloc5); delete [] puissancestab; return false; } // init tab for (unsigned * ptr=tab;ptr!=tabend;++ptr) *ptr=0; int l32=C32*32; vector< line_t > relations(axbmodn.size()); for (unsigned i=0;i2){ cout << i << ", p="; if (i==0) cout << "-1"; else { if (i<=bs) cout << basis[i-1].p << " " << relations[i].count << endl; else cout << endl; } } } if (debug_infolevel) *logptr(contextptr) << CLOCK() << " begin rref size " << relations.size() << "x" << l32 << " K " << 0.004*relations.size()*C32 << ", " << count0 << " null lines, " << count1 << " 1-line" << endl; #if 0 // debug only for (int i=0;i relations2(l32); i=0; int j=0,rs=int(relations.size()); for (;i p(bs), add_p(additional_primes.size()); for (int j=0;j=sqrtavals.size() || axbmodn[j].bindex>=bvals.size()) return false; // check added because ifactor(nextprime(alog10(17))*nextprime(alog10(19))); fails on Prime (and unable to do parallel debug in giac) update_xy(axbmodn[j],zx,zy,p,add_p,N,basis,additional_primes,sqrtavals,bvals,puissancestab,zq,zr,alloc1,alloc2,alloc3,alloc4,alloc5); #ifdef ADDITIONAL_PRIMES_HASHMAP unsigned u=largep(axbmodn[j],puissancestab); if (u) update_xy(additional_primes_map[u],zx,zy,p,add_p,N,basis,additional_primes,sqrtavals,bvals,puissancestab,zq,zr,alloc1,alloc2,alloc3,alloc4,alloc5); #endif } // end if (j6) *logptr(contextptr) << CLOCK() << gettext("checking gcd") << cur << " " << N << endl; if ( (cur.type==_INT_ && cur.val>7) || (cur.type==_ZINT && is_strictly_greater(n_orig,cur,contextptr))){ pn=cur; mpz_clear(zx); mpz_clear(zy); mpz_clear(zq); mpz_clear(zr); mpz_clear(alloc1); mpz_clear(alloc2); mpz_clear(alloc3); mpz_clear(alloc4); mpz_clear(alloc5); delete [] puissancestab; delete [] tab; return true; } } mpz_clear(zx); mpz_clear(zy); mpz_clear(zq); mpz_clear(zr); mpz_clear(alloc1); mpz_clear(alloc2); mpz_clear(alloc3); mpz_clear(alloc4); mpz_clear(alloc5); delete [] puissancestab; delete [] tab; return false; } // Pollard-rho algorithm const int POLLARD_GCD=64; #ifdef GIAC_MPQS #if defined(RTOS_THREADX) // !defined(BESTA_OS) const int POLLARD_MAXITER=3000; #else const int POLLARD_MAXITER=15000; #endif #else const int POLLARD_MAXITER=15000; #endif static gen pollard(gen n, gen k,GIAC_CONTEXT){ k.uncoerce(); n.uncoerce(); int maxiter=POLLARD_MAXITER; double nd=evalf_double(n,1,contextptr)._DOUBLE_val; #if defined(RTOS_THREADX) || defined(BESTA_OS) || defined NSPIRE int nd1=int(2000*(std::log10(nd)-34)); #else int nd1=int(1500*std::pow(16.,(std::log10(nd)-40)/10)); #endif if (nd1>maxiter) maxiter=nd1; int m,m1,a,a1,j; m1=m=2; a1=a=1; int c=0; mpz_t g,x,x1,x2,x2k,y,y1,p,q,tmpq,alloc1,alloc2,alloc3,alloc4,alloc5; mpz_init_set_si(g,1); // ? mp_init_size to specify size mpz_init_set_si(x,2); mpz_init_set_si(x1,2); mpz_init_set_si(y,2); mpz_init(y1); mpz_init(x2); mpz_init(x2k); mpz_init_set_si(p,1); mpz_init(q); mpz_init(tmpq); mpz_init(alloc1); mpz_init(alloc2); mpz_init(alloc3); mpz_init(alloc4); mpz_init(alloc5); while (!ctrl_c && !interrupted && mpz_cmp_si(g,1)==0) { #ifdef TIMEOUT control_c(); #endif a=2*a+1;//a=2^(e+1)-1=2*l(m)-1 while (!ctrl_c && !interrupted && mpz_cmp_si(g,1)==0 && a>m) { // ok #ifdef TIMEOUT control_c(); #endif // x=f(x,k,n,q); #ifdef USE_GMP_REPLACEMENTS mp_sqr(&x,&x2); mpz_add(x2k,x2,*k._ZINTptr); if (mpz_cmp(x2k,*n._ZINTptr)>0){ mp_grow(&alloc1,x2k.used+2); mpz_set_ui(alloc1,0); alloc1.used = x2k.used +2 ; mpz_set(alloc2,x2k); mpz_set(alloc3,*n._ZINTptr); // mpz_set_si(alloc4,0); // mpz_set_si(alloc5,0); alloc_mp_div(&x2k,n._ZINTptr,&tmpq,&x,&alloc1,&alloc2,&alloc3,&alloc4,&alloc5); } else mpz_set(x,x2k); #else mpz_mul(x2,x,x); mpz_add(x2k,x2,*k._ZINTptr); mpz_tdiv_r(x,x2k,*n._ZINTptr); #endif m += 1; if (debug_infolevel && ((m % #if defined(RTOS_THREADX) || defined(BESTA_OS) || defined NSPIRE (1<<10) #else (1<<18) #endif )==0)) *logptr(contextptr) << CLOCK() << gettext(" Pollard-rho try ") << m << endl; if (m > maxiter ){ if (debug_infolevel) *logptr(contextptr) << CLOCK() << gettext(" Pollard-rho failure, ntries ") << m << endl; mpz_clear(alloc5); mpz_clear(alloc4); mpz_clear(alloc3); mpz_clear(alloc2); mpz_clear(alloc1); mpz_clear(tmpq); mpz_clear(x); mpz_clear(x1); mpz_clear(x2); mpz_clear(x2k); mpz_clear(y); mpz_clear(y1); mpz_clear(p); mpz_clear(q); return -1; } // p=irem(p*(x1-x),n,q); mpz_sub(q,x1,x); mpz_mul(x2,p,q); #if 0 // def USE_GMP_REPLACEMENTS if (mpz_cmp(x2,*n._ZINTptr)>0){ mp_grow(&alloc1,x2.used+2); mpz_set_ui(alloc1,0); alloc1.used = x2.used +2 ; mpz_set(alloc2,x2); mpz_set(alloc3,*n._ZINTptr); // mpz_set_si(alloc4,0); // mpz_set_si(alloc5,0); alloc_mp_div(&x2,n._ZINTptr,&tmpq,&p,&alloc1,&alloc2,&alloc3,&alloc4,&alloc5); } else mpz_set(p,x2); #else mpz_tdiv_r(p,x2,*n._ZINTptr); #endif c += 1; if (c==POLLARD_GCD) { // g=gcd(abs(p,context0),n); mpz_abs(q,p); my_mpz_gcd(g,q,*n._ZINTptr); if (mpz_cmp_si(g,1)==0) { mpz_set(y,x); // y=x; mpz_set(y1,x1); // y1=x1; mpz_set_si(p,1); // p=1; a1=a; m1=m; c=0; } } }//m=a=2^e-1=l(m) if (mpz_cmp_si(g,1)==0) { mpz_set(x1,x); // x1=x;//x1=x_m=x_l(m)-1 j=3*(a+1)/2; // j=3*iquo(a+1,2); for (long i=m+1;i<=j;i++){ // x=f(x,k,n,q); mpz_mul(x2,x,x); mpz_add(x2k,x2,*k._ZINTptr); #if 0 // def USE_GMP_REPLACEMENTS if (mpz_cmp(x2k,*n._ZINTptr)>0){ mp_grow(&alloc1,x2k.used+2); mpz_set_ui(alloc1,0); alloc1.used = x2k.used +2 ; mpz_set(alloc2,x2k); mpz_set(alloc3,*n._ZINTptr); // mpz_set_si(alloc4,0); // mpz_set_si(alloc5,0); alloc_mp_div(&x2k,n._ZINTptr,&tmpq,&x,&alloc1,&alloc2,&alloc3,&alloc4,&alloc5); } else mpz_set(x,x2); #else mpz_tdiv_r(x,x2k,*n._ZINTptr); #endif } m=j; } } //g<>1 ds le paquet de POLLARD_GCD if (debug_infolevel>5) CERR << CLOCK() << " Pollard-rho nloops " << m << endl; mpz_set(x,y); // x=y; mpz_set(x1,y1); // x1=y1; mpz_set_si(g,1); // g=1; a=(a1-1)/2; // a=iquo(a1-1,2); m=m1; while (!ctrl_c && !interrupted && mpz_cmp_si(g,1)==0) { #ifdef TIMEOUT control_c(); #endif a=2*a+1; while (!ctrl_c && !interrupted && mpz_cmp_si(g,1)==0 && a>m) { // ok #ifdef TIMEOUT control_c(); #endif // x=f(x,k,n,q); mpz_mul(x2,x,x); mpz_add(x2k,x2,*k._ZINTptr); #if 0 // def USE_GMP_REPLACEMENTS if (mpz_cmp(x2k,*n._ZINTptr)>0){ mp_grow(&alloc1,x2k.used+2); mpz_set_ui(alloc1,0); alloc1.used = x2k.used +2 ; mpz_set(alloc2,x2k); mpz_set(alloc3,*n._ZINTptr); alloc_mp_div(&x2k,n._ZINTptr,&tmpq,&x,&alloc1,&alloc2,&alloc3,&alloc4,&alloc5); } else mpz_set(x,x2k); #else mpz_tdiv_r(x,x2k,*n._ZINTptr); #endif m += 1; if (m > maxiter ){ mpz_clear(alloc5); mpz_clear(alloc4); mpz_clear(alloc3); mpz_clear(alloc2); mpz_clear(alloc1); mpz_clear(tmpq); mpz_clear(x); mpz_clear(x1); mpz_clear(x2); mpz_clear(x2k); mpz_clear(y); mpz_clear(y1); mpz_clear(p); mpz_clear(q); return -1; } // p=irem(x1-x,n,q); mpz_sub(q,x1,x); #if 0 // def USE_GMP_REPLACEMENTS if (mpz_cmp(q,*n._ZINTptr)>0){ mp_grow(&alloc1,q.used+2); mpz_set_ui(alloc1,0); alloc1.used = q.used +2 ; mpz_set(alloc2,q); mpz_set(alloc3,*n._ZINTptr); // mpz_set_si(alloc4,0); // mpz_set_si(alloc5,0); alloc_mp_div(&q,n._ZINTptr,&tmpq,&p,&alloc1,&alloc2,&alloc3,&alloc4,&alloc5); } else mpz_set(p,q); #else mpz_tdiv_r(p,q,*n._ZINTptr); #endif // g=gcd(abs(p,context0),n); // ok mpz_abs(q,p); my_mpz_gcd(g,q,*n._ZINTptr); } if (mpz_cmp_si(g,1)==0) { mpz_set(x1,x); // x1=x; j=3*(a+1)/2; // j=3*iquo(a+1,2); for (long i=m+1;j>=i;i++){ // x=f(x,k,n,q); mpz_mul(x2,x,x); mpz_add(x2k,x2,*k._ZINTptr); mpz_tdiv_qr(tmpq,x,x2k,*n._ZINTptr); } m=j; } } mpz_clear(alloc5); mpz_clear(alloc4); mpz_clear(alloc3); mpz_clear(alloc2); mpz_clear(alloc1); mpz_clear(tmpq); mpz_clear(x); mpz_clear(x1); mpz_clear(x2); mpz_clear(x2k); mpz_clear(y); mpz_clear(y1); mpz_clear(p); mpz_clear(q); #ifdef TIMEOUT control_c(); #endif if (ctrl_c || interrupted){ mpz_clear(g); return 0; } if (mpz_cmp(g,*n._ZINTptr)==0) { if (k==1) { mpz_clear(g); return(pollard(n,-1,contextptr)); } else { if (k*k==1){ mpz_clear(g); return(pollard(n,3,contextptr)); } else { if (is_greater(k,50,contextptr)){ #if 1 return -1; #else ref_mpz_t * ptr=new ref_mpz_t; mpz_init_set(ptr->z,g); mpz_clear(g); return ptr; #endif } else { mpz_clear(g); return(pollard(n,k+2,contextptr)); } } } } ref_mpz_t * ptr=new ref_mpz_t; mpz_init_set(ptr->z,g); mpz_clear(g); return ptr; } // const short int giac_primes[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997}; bool eratosthene(double n,vector * & v){ static vector erato; v=&erato; if (n+1>erato.size()){ unsigned N=int(n); ++N; #if defined BESTA_OS if (N>2e6) return false; #else if (N>2e9) return false; #endif N = (N*11)/10; erato=vector(N+1,true); // insure that we won't recompute all again from start for ithprime(i+1) for (unsigned p=2;;++p){ while (!erato[p]) // find next prime ++p; if (p*p>N) // finished return true; for (unsigned i=2*p;i<=N;i+=p) erato[i]=false; // remove p multiples } } return true; } bool eratosthene2(double n,vector * & v){ static vector erato; v=&erato; if (n/2>=erato.size()){ unsigned N=int(n); ++N; #if defined BESTA_OS if (N>4e6) return false; #else if (N>2e9) return false; #endif // 11/20 insures that we won't recompute all again from start for ithprime(i+1) N = (N*11)/20; // keep only odd numbers in sieve erato=vector(N+1,true); //erato[i] stands for 2*i+1 <-> n corresponds to erato[n/2] for (unsigned p=3;;p+=2){ while (!erato[p/2]) // find next prime (first one is p==3) p+=2; if (p*p>2*N+1) // finished return true; // p is prime, set p*p, (p+2)*p, etc. to be non prime for (unsigned i=(p*p)/2;i<=N;i+=p) erato[i]=false; // remove p multiples } } return true; } // ithprime(n) is approx invli(n)+invli(sqrt(n))/4 where invli is reciproc. // of Li(x)=Ei(ln(x)) // For fast code, cf. https://github.com/kimwalisch/primecount static const char _ithprime_s []="ithprime"; static symbolic symb_ithprime(const gen & args){ return symbolic(at_ithprime,args); } static gen ithprime(const gen & g_,GIAC_CONTEXT){ gen g(g_); if (!is_integral(g)) return gentypeerr(contextptr); if (g.type!=_INT_) return gensizeerr(contextptr); // symb_ithprime(g); int i=g.val; if (i<0) return gensizeerr(contextptr); if (i==0) return 1; if (i<=int(sizeof(giac_primes)/sizeof(short int))) return giac_primes[i-1]; vector * vptr=0; #if 1 if (!eratosthene2(i*std::log(double(i))*1.1,vptr)) return gensizeerr(contextptr); unsigned count=2; unsigned s=unsigned(vptr->size()); for (unsigned k=2;ksize(); for (unsigned k=4;k * vptr=0; if (!eratosthene2(i+2,vptr)) return gensizeerr(contextptr); unsigned count=1; // 2 is prime, then count odd primes i=(i-1)/2; for (int k=1;k<=i;++k){ if ((*vptr)[k]) ++count; } return int(count); } gen _nprimes(const gen & args,GIAC_CONTEXT){ if ( args.type==_STRNG && args.subtype==-1) return args; if (args.type==_VECT) return apply(args,_nprimes,contextptr); return nprimes(args,contextptr); } static define_unary_function_eval (__nprimes,&giac::_nprimes,_nprimes_s); define_unary_function_ptr5( at_nprimes ,alias_at_nprimes,&__nprimes,0,true); bool is_divisible_by(const gen & n,unsigned long a){ if (n.type==_ZINT){ #ifdef USE_GMP_REPLACEMENTS mp_digit c; mp_mod_d(n._ZINTptr, a, &c); return c==0; #else return mpz_divisible_ui_p(*n._ZINTptr,a); #endif } return n.val%a==0; } // find trivial factors of n, // if add_last is true the remainder is put in the vecteur, // otherwise n contains the remainder vecteur pfacprem(gen & n,bool add_last,GIAC_CONTEXT){ gen a; gen q; int p,i,prime; vecteur v(2); vecteur u; if (is_zero(n)) return u; if (n.type==_ZINT){ ref_mpz_t * cur = new ref_mpz_t; mpz_t div,q,r,alloc1,alloc2,alloc3,alloc4,alloc5; mpz_set(cur->z,*n._ZINTptr); mpz_init_set(q,*n._ZINTptr); mpz_init(r); mpz_init(div); mpz_init(alloc1); mpz_init(alloc2); mpz_init(alloc3); mpz_init(alloc4); mpz_init(alloc5); for (i=0;iz,1)==0) break; prime=giac_primes[i]; mpz_set_ui(div,prime); #ifdef USE_GMP_REPLACEMENTS for (p=0;;p++){ mp_grow(&alloc1,cur->z.used+2); mpz_set_ui(alloc1,0); alloc1.used = cur->z.used +2 ; mpz_set(alloc2,cur->z); mpz_set(alloc3,div); alloc_mp_div(&cur->z,&div,&q,&r,&alloc1,&alloc2,&alloc3,&alloc4,&alloc5); // mpz_tdiv_qr(q,r,cur->z,div); if (mpz_cmp_si(r,0)) break; mp_exch(&cur->z,&q); } // *logptr(contextptr) << "Factor " << prime << " " << p << endl; if (p){ u.push_back(prime); u.push_back(p); } #else if (mpz_divisible_ui_p(cur->z,prime)){ mpz_set_ui(div,prime); for (p=0;;p++){ mpz_tdiv_qr(q,r,cur->z,div); if (mpz_cmp_si(r,0)) break; mpz_swap(cur->z,q); } // *logptr(contextptr) << "Factor " << prime << " " << p << endl; u.push_back(prime); u.push_back(p); } #endif } // end for on smal primes mpz_clear(alloc5); mpz_clear(alloc4); mpz_clear(alloc3); mpz_clear(alloc2); mpz_clear(alloc1); mpz_clear(div); mpz_clear(r); mpz_clear(q); n=cur; } else { for (i=0;iTerminal.MakeUnvisible(); #endif #endif return res; } #else // USE_GMP_REPLACEMENTS static gen pollardsieve(const gen &a,gen k,bool & do_pollard,GIAC_CONTEXT){ gen b=do_pollard?pollard(a,k,contextptr):-1; #ifdef TIMEOUT control_c(); #endif #ifdef GIAC_MPQS if (b==-1 && !ctrl_c && !interrupted){ do_pollard=false; if (msieve(a,b,contextptr)) return b; else return -1; } #endif if (b==-1) b=a; return b; } #endif // USE_GMP_REPLACEMENTS static gen ifactor2(const gen & n,vecteur & v,bool & do_pollard,GIAC_CONTEXT){ if (is_greater(giac_last_prime*giac_last_prime,n,contextptr) || is_probab_prime_p(n) ){ v.push_back(n); return 1; } // Check for power of integer: arg must be > 1e4, n*ln(arg)=d => n2 && i%2==0) || (i>3 && i%3==0) || (i>5 && i%5==0) || (i>7 && i%7==0) ) continue; gen u; if (i==2) u=isqrt(n); else { double x=std::pow(d,1./i); u=longlong(x); } if (pow(u,i,contextptr)==n){ vecteur w; do_pollard=true; ifactor2(u,w,do_pollard,contextptr); for (int j=0;j5) CERR << "Pollard begin " << CLOCK() << endl; bool do_pollard=true; gen a=ifactor2(n,v,do_pollard,contextptr); if (a==-1) return makevecteur(gensizeerr(gettext("Quadratic sieve failure, perhaps number too large"))); if (is_zero(a)) return makevecteur(gensizeerr(gettext("Stopped by user interruption"))); n=1; return v; } void mergeifactors(const vecteur & f,const vecteur &g,vecteur & h){ h=f; for (unsigned i=0;iempty()) return giac_ifactors(n0._VECTptr->front(),contextptr); #ifdef HAVE_LIBPARI #ifdef __APPLE__ return vecteur(1,gensizeerr(gettext("(Mac OS) Large number, you can try pari(); pari_factor(")+n0.print(contextptr)+")")); #endif if (!is_integer(n0) || is_zero(n0)) return vecteur(1,gensizeerr(gettext("ifactors"))); if (is_one(n0)) return vecteur(0); gen g(pari_ifactor(n0),contextptr); if (g.type==_VECT){ matrice m(mtran(*g._VECTptr)); vecteur res; const_iterateur it=m.begin(),itend=m.end(); for (;it!=itend;++it){ if (it->type!=_VECT) return vecteur(1,gensizeerr(gettext("ifactor.cc/ifactors"))); res.push_back(it->_VECTptr->front()); res.push_back(it->_VECTptr->back()); } return res; } #endif // LIBPARI return giac_ifactors(n0,contextptr); } vecteur ifactors(const gen & n0,GIAC_CONTEXT){ gen n(n0); vecteur f=pfacprem(n,false,contextptr); if (is_undef(f)) return f; vecteur g=ifactors1(n,contextptr); if (is_undef(g)) return g; return mergevecteur(f,g); } vecteur ifactors(const gen & r,const gen & i,const gen & ri,GIAC_CONTEXT){ gen norm=r*r+i*i; gen reste(ri); const vecteur & facto = ifactors(norm,contextptr); if (is_undef(facto)) return facto; int l=int(facto.size())/2; vecteur res; for (int i=0;i0;--mult,++multp){ if (!is_zero(reste % prime)) break; reste=reste/prime; } if (multp){ res.push_back(prime); res.push_back(multp); } if (mult){ prime=conj(prime,contextptr); res.push_back(prime); res.push_back(mult); reste=reste/pow(prime,mult,contextptr); } } if (!is_one(reste)){ res.insert(res.begin(),1); res.insert(res.begin(),reste); } return res; } gen ifactors(const gen & args,int maplemode,GIAC_CONTEXT){ if ( (args.type==_INT_) || (args.type==_ZINT)){ if (is_zero(args)){ if (maplemode==1) return makevecteur(args,vecteur(0)); else return makevecteur(args); } vecteur v(ifactors(abs(args,contextptr),contextptr)); // ok if (!v.empty() && is_undef(v.front())) return v.front(); if (maplemode!=1){ if (is_positive(args,context0)) return v; return mergevecteur(makevecteur(minus_one,plus_one),v); } vecteur res; const_iterateur it=v.begin(),itend=v.end(); for (;it!=itend;it+=2){ res.push_back(makevecteur(*it,*(it+1))); } if (is_positive(args,context0)) return makevecteur(plus_one,res); else return makevecteur(minus_one,res); } if (args.type==_CPLX && is_integer(*args._CPLXptr) && is_integer(*(args._CPLXptr+1))) return ifactors(*args._CPLXptr,*(args._CPLXptr+1),args,contextptr); return gentypeerr(gettext("ifactors")); } gen _ifactors(const gen & args,GIAC_CONTEXT){ if ( args.type==_STRNG && args.subtype==-1) return args; if (args.type==_VECT) return apply(args,_ifactors,contextptr); gen g(args); if (!is_integral(g)) return gensizeerr(contextptr); if (calc_mode(contextptr)==1){ // ggb returns factors repeted instead of multiplicites vecteur res; gen in=ifactors(g,0,contextptr); if (in.type==_VECT){ for (unsigned i=0;isize();i+=2){ gen f=in[i],m=in[i+1]; if (m.type==_INT_){ for (int j=0;jsommet; if (u==at_inv){ vecteur v=in_factors(gf._SYMBptr->feuille,contextptr); iterateur it=v.begin(),itend=v.end(); for (;it!=itend;it+=2) *(it+1)=-*(it+1); return v; } if (u==at_neg){ vecteur v=in_factors(gf._SYMBptr->feuille,contextptr); v.push_back(minus_one); v.push_back(plus_one); return v; } if ( (u==at_pow) && (gf._SYMBptr->feuille._VECTptr->back().type==_INT_) ){ vecteur v=in_factors(gf._SYMBptr->feuille._VECTptr->front(),contextptr); gen k=gf._SYMBptr->feuille._VECTptr->back(); iterateur it=v.begin(),itend=v.end(); for (;it!=itend;it+=2) *(it+1)=k* *(it+1); return v; } if (u!=at_prod) return makevecteur(gf,plus_one); vecteur res; const_iterateur it=gf._SYMBptr->feuille._VECTptr->begin(),itend=gf._SYMBptr->feuille._VECTptr->end(); for (;it!=itend;++it){ res=mergevecteur(res,in_factors(*it,contextptr)); } return res; } static vecteur in_factors1(const vecteur & res,GIAC_CONTEXT){ gen coeff(1); vecteur v; const_iterateur it=res.begin(),itend=res.end(); for (;it!=itend;it+=2){ if (lidnt(*it).empty()) coeff=coeff*(pow(*it,*(it+1),contextptr)); else v.push_back(makevecteur(*it,*(it+1))); } return makevecteur(coeff,v); } vecteur factors(const gen & g,const gen & x,GIAC_CONTEXT){ gen gf=factor(g,x,false,contextptr); vecteur res=in_factors(gf,contextptr); if (xcas_mode(contextptr)!=1) return res; return in_factors1(res,contextptr); } static const char _factors_s []="factors"; gen _factors(const gen & args,GIAC_CONTEXT){ if ( args.type==_STRNG && args.subtype==-1) return args; if (args.type==_VECT && args.subtype==_SEQ__VECT && args._VECTptr->size()==2){ gen j=args._VECTptr->back(); gen res=_factors(args._VECTptr->front()*j,contextptr); if (res.type==_VECT && xcas_mode(contextptr)!=1) res=in_factors1(*res._VECTptr,contextptr); if (res.type==_VECT && res._VECTptr->size()==2){ res._VECTptr->front()=recursive_normal(res._VECTptr->front()/j,contextptr); if (xcas_mode(contextptr)!=1){ if (is_one(res._VECTptr->front())) res=res._VECTptr->back(); else { j=res._VECTptr->front(); res=res._VECTptr->back(); if (res.type==_VECT) res=mergevecteur(makevecteur(j,1),*res._VECTptr); } vecteur v; aplatir(*res._VECTptr,v,contextptr); res=v; } } return res; } if (args.type==_VECT) return apply(args,_factors,contextptr); return factors(args,vx_var,contextptr); } static define_unary_function_eval (__factors,&giac::_factors,_factors_s); define_unary_function_ptr5( at_factors ,alias_at_factors,&__factors,0,true); static gen ifactors2ifactor(const vecteur & l,bool quote){ int s; s=int(l.size()); gen r; vecteur v(s/2); for (int j=0;jsize()==1 && is_integer(n._VECTptr->front())) return ifactor(n,contextptr); if (n.type==_VECT) return apply(n,_ifactor,contextptr); if (!is_integral(n)) return gensizeerr(contextptr); if (is_strictly_positive(-n,0)) return -_ifactor(-n,contextptr); if (n.type==_INT_ && n.val<=3) return n; return ifactor(n,contextptr); } static const char _ifactor_s []="ifactor"; static define_unary_function_eval (__ifactor,&_ifactor,_ifactor_s); define_unary_function_ptr5( at_ifactor ,alias_at_ifactor,&__ifactor,0,true); static const char _factoriser_entier_s []="factoriser_entier"; static define_unary_function_eval (__factoriser_entier,&_ifactor,_factoriser_entier_s); define_unary_function_ptr5( at_factoriser_entier ,alias_at_factoriser_entier,&__factoriser_entier,0,true); static vecteur divis(const vecteur & l3,GIAC_CONTEXT){ vecteur l1(1); gen d,e; int s=int(l3.size()); gen taille=1; for (int k=0;kLIST_SIZE_LIMIT) return vecteur(1,gendimerr(contextptr)); l1.reserve(taille.val); l1[0]=1;//l3.push_back(..); for (int k=0;ksize()!=4) ) return gensizeerr(contextptr); vecteur a(2).type==_STRNG && args.subtype==-1{ if ( (args.type!=_VECT) || (args._VECTptr->size()!=4) ) return gensizeerr(contextptr); vecteur a(2))) return args){ if ( (args.type!=_VECT) || (args._VECTptr->size()!=4) ) return gensizeerr(contextptr); vecteur a(2); if ( (args.type!=_VECT) || (args._VECTptr->size()!=4) ) return gensizeerr(contextptr); vecteur a(2),b(2); a[0]=args[0]; a[1]=args[1]; b[0]=args[2]; b[1]=args[3]; //gen a=args[0],p=args[1], b=args[2],q=args[3]; return ichinreme(a,b); } static const char _ichinreme_s []="ichinreme"; static define_unary_function_eval (__ichinreme,&_ichinreme,_ichinreme_s); define_unary_function_ptr5( at_ichinreme ,alias_at_ichinreme,&__ichinreme,0,true); */ gen euler(const gen & e,GIAC_CONTEXT){ if (e==0) return e; vecteur v(ifactors(e,contextptr)); if (!v.empty() && is_undef(v.front())) return v.front(); const_iterateur it=v.begin(),itend=v.end(); for (gen res(plus_one);;){ if (it==itend) return res; gen p=*it; ++it; int n=it->val; res = res * (p-plus_one)*pow(p,n-1); ++it; } } static const char _euler_s []="euler"; gen _euler(const gen & args,GIAC_CONTEXT){ if ( args.type==_STRNG && args.subtype==-1) return args; if (args.type==_VECT) return apply(args,_euler,contextptr); if ( is_integer(args) && is_positive(args,contextptr)) return euler(args,contextptr); return gentypeerr(contextptr); } static define_unary_function_eval (__euler,&giac::_euler,_euler_s); define_unary_function_ptr5( at_euler ,alias_at_euler,&__euler,0,true); gen pa2b2(const gen & p,GIAC_CONTEXT){ if (p==2) return makevecteur(1,1); if (!is_integer(p) || (p%4)!=1 || is_greater(1,p,contextptr)) return gensizeerr(contextptr);// car p!=1 mod 4 gen q=(p-1)/4; gen a=2; gen ra; ra=powmod(a,q,p); //on cherche ra^2=-1 mod p avec ra!=1 et ra !=p-1 while ((a!=p-1) && ((ra==1)|| (ra==p-1))){ a=a+1; ra=powmod(a,q,p); } if ((ra==1)||(ra==p-1)) return gensizeerr(contextptr);//car p n'est pas premier gen ux=1,uy=ra,vx=0,vy=p,wx,wy; gen m=1; while(m!=0){ if (is_positive(vx*vx+vy*vy-ux*ux+uy*uy,0)){ //on echange u et v wx=vx; wy=vy; vx=ux; vy=uy; ux=wx; uy=wy; } gen alpha=inv(2,contextptr)-(ux*vx+uy*vy)*inv(vx*vx+vy*vy,contextptr); //m=partie entiere de alpha (-v.v/2<(u+mv).v<=v.v/2) m=_floor(alpha,contextptr); ux=ux+m*vx; uy=uy+m*vy; } vecteur v(2); //v repond a la question v[0]=abs(vx,contextptr); // ok v[1]=abs(vy,contextptr); // ok if (vx*vx+vy*vy!=p) return gensizeerr(contextptr); return v; } gen _pa2b2(const gen & args,GIAC_CONTEXT){ if ( args.type==_STRNG && args.subtype==-1) return args; if (!is_integer(args)) return gensizeerr(contextptr); gen n=args; return pa2b2(n,contextptr); } static const char _pa2b2_s []="pa2b2"; static define_unary_function_eval (__pa2b2,&_pa2b2,_pa2b2_s); define_unary_function_ptr5( at_pa2b2 ,alias_at_pa2b2,&__pa2b2,0,true); static gen ipropfrac(const gen & a,const gen & b,GIAC_CONTEXT){ if (!is_integer(a) || !is_integer(b)) return gensizeerr(contextptr); gen r=a%b; gen q=(a-r)/b; gen d=gcd(r,b); r=r/d; gen b1=b/d; if (r==0) return q; gen v; v=symbolic(at_division,gen(makevecteur(r,b1),_SEQ__VECT)); gen w; w=symbolic(at_plus,gen(makevecteur(q,v),_SEQ__VECT)); if (calc_mode(contextptr)==1) return symbolic(at_quote,w); return w; } gen _propfrac(const gen & arg,GIAC_CONTEXT){ if ( arg.type==_STRNG && arg.subtype==-1) return arg; gen args(arg); vecteur v; if (arg.type==_VECT && arg._VECTptr->size()==2){ v=vecteur(1,arg._VECTptr->back()); args=arg._VECTptr->front(); lvar(args,v); } else v=lvar(arg); gen g=e2r(args,v,contextptr); gen a,b; fxnd(g,a,b); if (v.empty()) return ipropfrac(a,b,contextptr); else { gen d=r2e(b,v,contextptr); g=_quorem(makesequence(r2e(a,v,contextptr),d,v.front()),contextptr); if (is_undef(g)) return g; vecteur &v=*g._VECTptr; return v[0]+rdiv(v[1],d,contextptr); } } static const char _propfrac_s []="propfrac"; static define_unary_function_eval (__propfrac,&_propfrac,_propfrac_s); define_unary_function_ptr5( at_propfrac ,alias_at_propfrac,&__propfrac,0,true); void step_egcd(int a,int b,GIAC_CONTEXT){ gprintf("===============",vecteur(0),1,contextptr); gprintf("Extended Euclide algorithm for a=%gen and b=%gen",makevecteur(a,b),1,contextptr); gprintf("L%gen: 1*a+0*b=%gen",makevecteur(1,a),1,contextptr); gprintf("L%gen: 0*a+1*b=%gen",makevecteur(2,b),1,contextptr); int i=3; int u0=1,v0=0,u1=0,v1=1,u2,v2; for (;b;++i){ int q=a/b; u2=u0-q*u1; v2=v0-q*v1; int r=a-q*b; gprintf("iquo(%gen,%gen)=%gen",makevecteur(a,b,q),1,contextptr); gprintf("L%gen=L%gen-%gen*L%gen: %gen*a+%gen*b=%gen",makevecteur(i,i-2,q,i-1,u2,v2,r),1,contextptr); u0=u1; u1=u2; v0=v1; v1=v2; a=b; b=r; } gprintf("Bezout identity %gen*a+%gen*b=%gen",makevecteur(u0,v0,a),1,contextptr); } gen iabcuv(const gen & a,const gen & b,const gen & c,GIAC_CONTEXT){ gen d=gcd(a,b); if (c%d!=0) return gensizeerr(gettext("No solution in ring")); gen a1=a/d,b1=b/d,c1=c/d; gen u,v,w; if (a1.type==_INT_ && b1.type==_INT_ && step_infolevel(contextptr)) step_egcd(a1.val,b1.val,contextptr); egcd(a1,b1,u,v,w); vecteur r(2); r[0]=smod(u*c1,b); r[1]=iquo(c-r[0]*a,b); return r; } gen _iabcuv(const gen & args,GIAC_CONTEXT){ if ( args.type==_STRNG && args.subtype==-1) return args; if ( (args.type!=_VECT) || (args._VECTptr->size()!=3) ) return gensizeerr(contextptr); gen a=args[0],b=args[1],c=args[2]; return iabcuv(a,b,c,contextptr); } static const char _iabcuv_s []="iabcuv"; static define_unary_function_eval (__iabcuv,&_iabcuv,_iabcuv_s); define_unary_function_ptr5( at_iabcuv ,alias_at_iabcuv,&__iabcuv,0,true); gen abcuv(const gen & a,const gen & b,const gen & c,const gen & x,GIAC_CONTEXT){ gen g=_egcd(makesequence(a,b,x),contextptr); if (is_undef(g)) return g; vecteur & v=*g._VECTptr; gen h=_quorem(makesequence(c,v[2],x),contextptr); if (is_undef(h)) return h; vecteur & w=*h._VECTptr; if (!is_zero(w[1])) return gensizeerr(gettext("No solution in ring")); gen U=v[0]*w[0],V=v[1]*w[0]; if (_degree(makesequence(c,x),contextptr).val<_degree(makesequence(a,x),contextptr).val+_degree(makesequence(b,x),contextptr).val ){ U=_rem(makesequence(U,b,x),contextptr); V=_rem(makesequence(V,a,x),contextptr); } return makevecteur(U,V); } gen _abcuv(const gen & args,GIAC_CONTEXT){ if ( args.type==_STRNG && args.subtype==-1) return args; if ( (args.type!=_VECT) || (args._VECTptr->size()<3) ) return gensizeerr(contextptr); vecteur & v =*args._VECTptr; if (v.size()>3) return abcuv(v[0],v[1],v[2],v[3],contextptr); return abcuv(v[0],v[1],v[2],vx_var,contextptr); } static const char _abcuv_s []="abcuv"; static define_unary_function_eval (__abcuv,&_abcuv,_abcuv_s); define_unary_function_ptr5( at_abcuv ,alias_at_abcuv,&__abcuv,0,true); gen simp2(const gen & a,const gen & b,GIAC_CONTEXT){ vecteur r(2); gen d=gcd(a,b); r[0]=normal(a/d,contextptr); r[1]=normal(b/d,contextptr); return r; } gen _simp2(const gen & args,GIAC_CONTEXT){ if ( args.type==_STRNG && args.subtype==-1) return args; if ( (args.type!=_VECT) || (args._VECTptr->size()!=2) ) return gensizeerr(contextptr); gen a=args[0],b=args[1]; if ( (a.type==_VECT) || (b.type==_VECT) ) return gensizeerr(contextptr); return simp2(a,b,contextptr); } static const char _simp2_s []="simp2"; static define_unary_function_eval (__simp2,&_simp2,_simp2_s); define_unary_function_ptr5( at_simp2 ,alias_at_simp2,&__simp2,0,true); gen fxnd(const gen & a){ vecteur v(lvar(a)); gen g=e2r(a,v,context0); // ok gen n,d; fxnd(g,n,d); return makevecteur(r2e(n,v,context0),r2e(d,v,context0)); // ok } gen _fxnd(const gen & args,GIAC_CONTEXT){ if ( args.type==_STRNG && args.subtype==-1) return args; if (args.type==_VECT) return apply(args,fxnd); return fxnd(args); } static const char _fxnd_s []="fxnd"; static define_unary_function_eval (__fxnd,&_fxnd,_fxnd_s); define_unary_function_ptr5( at_fxnd ,alias_at_fxnd,&__fxnd,0,true); #ifndef NO_NAMESPACE_GIAC } // namespace giac #endif // ndef NO_NAMESPACE_GIAC