source: git/libpolys/coeffs/modulop.cc @ 850277

spielwiese
Last change on this file since 850277 was 850277, checked in by Hans Schoenemann <hannes@…>, 10 years ago
chg: moved reading/writing numbers via ssi to coeffs (p.1)
  • Property mode set to 100644
File size: 16.1 KB
Line 
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/*
5* ABSTRACT: numbers modulo p (<=32003)
6*/
7
8#ifdef HAVE_CONFIG_H
9#include "libpolysconfig.h"
10#endif /* HAVE_CONFIG_H */
11#include <misc/auxiliary.h>
12
13#include <factory/factory.h>
14
15#include <string.h>
16#include <omalloc/omalloc.h>
17#include <coeffs/coeffs.h>
18#include <reporter/reporter.h>
19#include <coeffs/numbers.h>
20#include <coeffs/longrat.h>
21#include <coeffs/mpr_complex.h>
22#include <misc/mylimits.h>
23#include <coeffs/modulop.h>
24
25// int npGen=0;
26
27/// Our Type!
28static const n_coeffType ID = n_Zp;
29
30#ifdef NV_OPS
31#pragma GCC diagnostic ignored "-Wlong-long"
32static inline number nvMultM(number a, number b, const coeffs r)
33{
34  assume( getCoeffType(r) == ID );
35
36#if SIZEOF_LONG == 4
37#define ULONG64 (unsigned long long)(unsigned long)
38#else
39#define ULONG64 (unsigned long)
40#endif
41  return (number)
42      (unsigned long)((ULONG64 a)*(ULONG64 b) % (ULONG64 r->ch));
43}
44number  nvMult        (number a, number b, const coeffs r);
45number  nvDiv         (number a, number b, const coeffs r);
46number  nvInvers      (number c, const coeffs r);
47void    nvPower       (number a, int i, number * result, const coeffs r);
48#endif
49
50
51
52
53BOOLEAN npGreaterZero (number k, const coeffs r)
54{
55  assume( n_Test(k, r) );
56
57  int h = (int)((long) k);
58  return ((int)h !=0) && (h <= (r->ch>>1));
59}
60
61//unsigned long npMultMod(unsigned long a, unsigned long b, int npPrimeM)
62//{
63//  unsigned long c = a*b;
64//  c = c % npPrimeM;
65//  assume(c == (unsigned long) npMultM((number) a, (number) b, npPrimeM));
66//  return c;
67//}
68
69number npMult (number a,number b, const coeffs r)
70{
71  assume( n_Test(a, r) );
72  assume( n_Test(b, r) );
73
74  if (((long)a == 0) || ((long)b == 0))
75    return (number)0;
76  number c = npMultM(a,b, r);
77  assume( n_Test(c, r) );
78  return c;
79}
80
81/*2
82* create a number from int
83*/
84number npInit (long i, const coeffs r)
85{
86  long ii=i % (long)r->ch;
87  if (ii <  0L)                         ii += (long)r->ch;
88
89  number c = (number)ii;
90  assume( n_Test(c, r) );
91  return c;
92
93}
94
95
96/*2
97 * convert a number to an int in (-p/2 .. p/2]
98 */
99int npInt(number &n, const coeffs r)
100{
101  assume( n_Test(n, r) );
102
103  if ((long)n > (((long)r->ch) >>1)) return (int)((long)n -((long)r->ch));
104  else                               return (int)((long)n);
105}
106
107number npAdd (number a, number b, const coeffs r)
108{
109  assume( n_Test(a, r) );
110  assume( n_Test(b, r) );
111
112  number c = npAddM(a,b, r);
113
114  assume( n_Test(c, r) );
115
116  return c;
117}
118
119number npSub (number a, number b, const coeffs r)
120{
121  assume( n_Test(a, r) );
122  assume( n_Test(b, r) );
123
124  number c = npSubM(a,b,r);
125
126  assume( n_Test(c, r) );
127
128  return c;
129}
130
131BOOLEAN npIsZero (number  a, const coeffs r)
132{
133  assume( n_Test(a, r) );
134
135  return 0 == (long)a;
136}
137
138BOOLEAN npIsOne (number a, const coeffs r)
139{
140  assume( n_Test(a, r) );
141
142  return 1 == (long)a;
143}
144
145BOOLEAN npIsMOne (number a, const coeffs r)
146{
147  assume( n_Test(a, r) );
148
149  return ((r->npPminus1M == (long)a)&&((long)1!=(long)a));
150}
151
152#ifdef HAVE_DIV_MOD
153
154#ifdef USE_NTL_XGCD
155
156//ifdef HAVE_NTL // in ntl.a
157//extern void XGCD(long& d, long& s, long& t, long a, long b);
158#include <NTL/ZZ.h>
159#ifdef NTL_CLIENT
160NTL_CLIENT
161#endif
162
163#endif
164
165long InvMod(long a, const coeffs R)
166{
167   long d, s, t;
168
169#ifdef USE_NTL_XGCD
170   XGCD(d, s, t, a, R->ch);
171   assume (d == 1);
172#else
173   long  u, v, u0, v0, u1, v1, u2, v2, q, r;
174
175   assume(a>0);
176   u1=1; u2=0;
177   u = a; v = R->ch;
178
179   while (v != 0)
180   {
181      q = u / v;
182      r = u % v;
183      u = v;
184      v = r;
185      u0 = u2;
186      u2 = u1 - q*u2;
187      u1 = u0;
188   }
189
190   assume(u==1);
191   s = u1;
192#endif
193   if (s < 0)
194      return s + R->ch;
195   else
196      return s;
197}
198#endif
199
200inline number npInversM (number c, const coeffs r)
201{
202  assume( n_Test(c, r) );
203#ifndef HAVE_DIV_MOD
204  number d = (number)(long)r->npExpTable[r->npPminus1M - r->npLogTable[(long)c]];
205#else
206  long inv=(long)r->npInvTable[(long)c];
207  if (inv==0)
208  {
209    inv=InvMod((long)c,r);
210    r->npInvTable[(long)c]=inv;
211  }
212  number d = (number)inv;
213#endif
214  assume( n_Test(d, r) );
215  return d;
216
217}
218
219number npDiv (number a,number b, const coeffs r)
220{
221  assume( n_Test(a, r) );
222  assume( n_Test(b, r) );
223
224//#ifdef NV_OPS
225//  if (r->ch>NV_MAX_PRIME)
226//    return nvDiv(a,b);
227//#endif
228  if ((long)a==0)
229    return (number)0;
230  number d;
231
232#ifndef HAVE_DIV_MOD
233  if ((long)b==0)
234  {
235    WerrorS(nDivBy0);
236    return (number)0;
237  }
238
239  int s = r->npLogTable[(long)a] - r->npLogTable[(long)b];
240  if (s < 0)
241    s += r->npPminus1M;
242  d = (number)(long)r->npExpTable[s];
243#else
244  number inv=npInversM(b,r);
245  d = npMultM(a,inv,r);
246#endif
247
248  assume( n_Test(d, r) );
249  return d;
250
251}
252number  npInvers (number c, const coeffs r)
253{
254  assume( n_Test(c, r) );
255
256  if ((long)c==0)
257  {
258    WerrorS("1/0");
259    return (number)0;
260  }
261  number d = npInversM(c,r);
262
263  assume( n_Test(d, r) );
264  return d;
265
266}
267
268number npNeg (number c, const coeffs r)
269{
270  assume( n_Test(c, r) );
271
272  if ((long)c==0) return c;
273
274#if 0
275  number d = npNegM(c,r);
276  assume( n_Test(d, r) );
277  return d;
278#else
279  c = npNegM(c,r);
280  assume( n_Test(c, r) );
281  return c;
282#endif
283}
284
285BOOLEAN npGreater (number a,number b, const coeffs r)
286{
287  assume( n_Test(a, r) );
288  assume( n_Test(b, r) );
289
290  //return (long)a != (long)b;
291  return (long)a > (long)b;
292}
293
294BOOLEAN npEqual (number a,number b, const coeffs r)
295{
296  assume( n_Test(a, r) );
297  assume( n_Test(b, r) );
298
299//  return (long)a == (long)b;
300
301  return npEqualM(a,b,r);
302}
303
304void npWrite (number &a, const coeffs r)
305{
306  assume( n_Test(a, r) );
307
308  if ((long)a>(((long)r->ch) >>1)) StringAppend("-%d",(int)(((long)r->ch)-((long)a)));
309  else                             StringAppend("%d",(int)((long)a));
310}
311
312void npPower (number a, int i, number * result, const coeffs r)
313{
314  assume( n_Test(a, r) );
315
316  if (i==0)
317  {
318    //npInit(1,result);
319    *(long *)result = 1;
320  }
321  else if (i==1)
322  {
323    *result = a;
324  }
325  else
326  {
327    npPower(a,i-1,result,r);
328    *result = npMultM(a,*result,r);
329  }
330}
331
332static const char* npEati(const char *s, int *i, const coeffs r)
333{
334
335  if (((*s) >= '0') && ((*s) <= '9'))
336  {
337    unsigned long ii=0L;
338    do
339    {
340      ii *= 10;
341      ii += *s++ - '0';
342      if (ii >= (MAX_INT_VAL / 10)) ii = ii % r->ch;
343    }
344    while (((*s) >= '0') && ((*s) <= '9'));
345    if (ii >= (unsigned long)r->ch) ii = ii % r->ch;
346    *i=(int)ii;
347  }
348  else (*i) = 1;
349  return s;
350}
351
352const char * npRead (const char *s, number *a, const coeffs r)
353{
354  int z;
355  int n=1;
356
357  s = npEati(s, &z, r);
358  if ((*s) == '/')
359  {
360    s++;
361    s = npEati(s, &n, r);
362  }
363  if (n == 1)
364    *a = (number)(long)z;
365  else
366  {
367    if ((z==0)&&(n==0)) WerrorS(nDivBy0);
368    else
369    {
370#ifdef NV_OPS
371      if (r->ch>NV_MAX_PRIME)
372        *a = nvDiv((number)(long)z,(number)(long)n,r);
373      else
374#endif
375        *a = npDiv((number)(long)z,(number)(long)n,r);
376    }
377  }
378  assume( n_Test(*a, r) );
379  return s;
380}
381
382/*2
383* set the charcteristic (allocate and init tables)
384*/
385
386void npKillChar(coeffs r)
387{
388  #ifdef HAVE_DIV_MOD
389  if (r->npInvTable!=NULL)
390  omFreeSize( (void *)r->npInvTable, r->ch*sizeof(unsigned short) );
391  r->npInvTable=NULL;
392  #else
393  if (r->npExpTable!=NULL)
394  {
395    omFreeSize( (void *)r->npExpTable, r->ch*sizeof(unsigned short) );
396    omFreeSize( (void *)r->npLogTable, r->ch*sizeof(unsigned short) );
397    r->npExpTable=NULL; r->npLogTable=NULL;
398  }
399  #endif
400}
401
402static BOOLEAN npCoeffsEqual(const coeffs r, n_coeffType n, void * parameter)
403{
404  /* test, if r is an instance of nInitCoeffs(n,parameter) */
405  return (n==n_Zp) && (r->ch==(int)(long)parameter);
406}
407CanonicalForm npConvSingNFactoryN( number n, BOOLEAN setChar, const coeffs r )
408{
409  if (setChar) setCharacteristic( r->ch );
410  CanonicalForm term(npInt( n,r ));
411  return term;
412}
413
414number npConvFactoryNSingN( const CanonicalForm n, const coeffs r)
415{
416  if (n.isImm())
417  {
418    return npInit(n.intval(),r);
419  }
420  else
421  {
422    assume(0);
423    return NULL;
424  }
425}
426
427static char* npCoeffString(const coeffs r)
428{
429  char *s=(char*)omAlloc(11);
430  snprintf(s,11,"%d",r->ch);
431  return s;
432}
433
434static void npWriteFd(number n, FILE* f, const coeffs r)
435{
436  fprintf(f,"%d ",(int)(long)n);
437}
438
439static number npReadFd(s_buff f, const coeffs r)
440{
441  // read int
442  int dd;
443  dd=s_readint(f);
444  return (number)(long)dd;
445}
446
447BOOLEAN npInitChar(coeffs r, void* p)
448{
449  assume( getCoeffType(r) == ID );
450  const int c = (int) (long) p;
451
452  assume( c > 0 );
453
454  int i, w;
455
456  r->ch = c;
457  r->npPminus1M = c /*r->ch*/ - 1;
458
459  //r->cfInitChar=npInitChar;
460  r->cfKillChar=npKillChar;
461  r->nCoeffIsEqual=npCoeffsEqual;
462  r->cfCoeffString=npCoeffString;
463
464  r->cfMult  = npMult;
465  r->cfSub   = npSub;
466  r->cfAdd   = npAdd;
467  r->cfDiv   = npDiv;
468  r->cfIntDiv= npDiv;
469  //r->cfIntMod= ndIntMod;
470  r->cfExactDiv= npDiv;
471  r->cfInit = npInit;
472  //r->cfSize  = ndSize;
473  r->cfInt  = npInt;
474  #ifdef HAVE_RINGS
475  //r->cfDivComp = NULL; // only for ring stuff
476  //r->cfIsUnit = NULL; // only for ring stuff
477  //r->cfGetUnit = NULL; // only for ring stuff
478  //r->cfExtGcd = NULL; // only for ring stuff
479  // r->cfDivBy = NULL; // only for ring stuff
480  #endif
481  r->cfNeg   = npNeg;
482  r->cfInvers= npInvers;
483  //r->cfCopy  = ndCopy;
484  //r->cfRePart = ndCopy;
485  //r->cfImPart = ndReturn0;
486  r->cfWriteLong = npWrite;
487  r->cfRead = npRead;
488  //r->cfNormalize=ndNormalize;
489  r->cfGreater = npGreater;
490  r->cfEqual = npEqual;
491  r->cfIsZero = npIsZero;
492  r->cfIsOne = npIsOne;
493  r->cfIsMOne = npIsMOne;
494  r->cfGreaterZero = npGreaterZero;
495  r->cfPower = npPower;
496  r->cfGetDenom = ndGetDenom;
497  r->cfGetNumerator = ndGetNumerator;
498  //r->cfGcd  = ndGcd;
499  //r->cfLcm  = ndGcd;
500  //r->cfDelete= ndDelete;
501  r->cfSetMap = npSetMap;
502  //r->cfName = ndName;
503  r->cfInpMult=ndInpMult;
504  r->cfInit_bigint= nlModP; // npMap0;
505#ifdef NV_OPS
506  if (c>NV_MAX_PRIME)
507  {
508    r->cfMult  = nvMult;
509    r->cfDiv   = nvDiv;
510    r->cfExactDiv= nvDiv;
511    r->cfInvers= nvInvers;
512    r->cfPower= nvPower;
513  }
514#endif
515  r->cfCoeffWrite=npCoeffWrite;
516#ifdef LDEBUG
517  // debug stuff
518  r->cfDBTest=npDBTest;
519#endif
520
521  r->convSingNFactoryN=npConvSingNFactoryN;
522  r->convFactoryNSingN=npConvFactoryNSingN;
523
524  // io via ssi
525  r->cfWriteFd=npWriteFd;
526  r->cfReadFd=npReadFd;
527
528  // the variables:
529  r->nNULL = (number)0;
530  r->type = n_Zp;
531  r->ch = c;
532  r->has_simple_Alloc=TRUE;
533  r->has_simple_Inverse=TRUE;
534
535  // the tables
536#ifdef NV_OPS
537  if (r->ch <=NV_MAX_PRIME)
538#endif
539  {
540#if !defined(HAVE_DIV_MOD) || !defined(HAVE_MULT_MOD)
541    r->npExpTable=(unsigned short *)omAlloc( r->ch*sizeof(unsigned short) );
542    r->npLogTable=(unsigned short *)omAlloc( r->ch*sizeof(unsigned short) );
543    r->npExpTable[0] = 1;
544    r->npLogTable[0] = 0;
545    if (r->ch > 2)
546    {
547      w = 1;
548      loop
549      {
550        r->npLogTable[1] = 0;
551        w++;
552        i = 0;
553        loop
554        {
555          i++;
556          r->npExpTable[i] =(int)(((long)w * (long)r->npExpTable[i-1])
557                               % r->ch);
558          r->npLogTable[r->npExpTable[i]] = i;
559          if /*(i == r->ch - 1 ) ||*/ (/*(*/ r->npExpTable[i] == 1 /*)*/)
560            break;
561        }
562        if (i == r->ch - 1)
563          break;
564      }
565    }
566    else
567    {
568      r->npExpTable[1] = 1;
569      r->npLogTable[1] = 0;
570    }
571#endif
572#ifdef HAVE_DIV_MOD
573    r->npInvTable=(unsigned short*)omAlloc0( r->ch*sizeof(unsigned short) );
574#endif
575  }
576  return FALSE;
577}
578
579#ifdef LDEBUG
580BOOLEAN npDBTest (number a, const char *f, const int l, const coeffs r)
581{
582  if (((long)a<0) || ((long)a>r->ch))
583  {
584    Print("wrong mod p number %ld at %s,%d\n",(long)a,f,l);
585    return FALSE;
586  }
587  return TRUE;
588}
589#endif
590
591number npMapP(number from, const coeffs src, const coeffs dst_r)
592{
593  long i = (long)from;
594  if (i>src->ch/2)
595  {
596    i-=src->ch;
597    while (i < 0) i+=dst_r->ch;
598  }
599  i%=dst_r->ch;
600  return (number)i;
601}
602
603static number npMapLongR(number from, const coeffs /*src*/, const coeffs dst_r)
604{
605  gmp_float *ff=(gmp_float*)from;
606  mpf_t *f=ff->_mpfp();
607  number res;
608  mpz_ptr dest,ndest;
609  int size,i;
610  int e,al,bl;
611  long iz;
612  mp_ptr qp,dd,nn;
613
614  size = (*f)[0]._mp_size;
615  if (size == 0)
616    return npInit(0,dst_r);
617  if(size<0)
618    size = -size;
619
620  qp = (*f)[0]._mp_d;
621  while(qp[0]==0)
622  {
623    qp++;
624    size--;
625  }
626
627  if(dst_r->ch>2)
628    e=(*f)[0]._mp_exp-size;
629  else
630    e=0;
631  res = ALLOC_RNUMBER();
632#if defined(LDEBUG)
633  res->debug=123456;
634#endif
635  dest = res->z;
636
637  long in=0;
638  if (e<0)
639  {
640    al = dest->_mp_size = size;
641    if (al<2) al = 2;
642    dd = (mp_ptr)omAlloc(sizeof(mp_limb_t)*al);
643    for (i=0;i<size;i++) dd[i] = qp[i];
644    bl = 1-e;
645    nn = (mp_ptr)omAlloc(sizeof(mp_limb_t)*bl);
646    nn[bl-1] = 1;
647    for (i=bl-2;i>=0;i--) nn[i] = 0;
648    ndest = res->n;
649    ndest->_mp_d = nn;
650    ndest->_mp_alloc = ndest->_mp_size = bl;
651    res->s = 0;
652    in=mpz_fdiv_ui(ndest,dst_r->ch);
653    mpz_clear(ndest);
654  }
655  else
656  {
657    al = dest->_mp_size = size+e;
658    if (al<2) al = 2;
659    dd = (mp_ptr)omAlloc(sizeof(mp_limb_t)*al);
660    for (i=0;i<size;i++) dd[i+e] = qp[i];
661    for (i=0;i<e;i++) dd[i] = 0;
662    res->s = 3;
663  }
664
665  dest->_mp_d = dd;
666  dest->_mp_alloc = al;
667  iz=mpz_fdiv_ui(dest,dst_r->ch);
668  mpz_clear(dest);
669  if(res->s==0)
670    iz=(long)npDiv((number)iz,(number)in,dst_r);
671  FREE_RNUMBER(res); // Q!?
672  return (number)iz;
673}
674
675#ifdef HAVE_RINGS
676/*2
677* convert from a GMP integer
678*/
679number npMapGMP(number from, const coeffs /*src*/, const coeffs dst)
680{
681  int_number erg = (int_number) omAlloc(sizeof(mpz_t)); // evtl. spaeter mit bin
682  mpz_init(erg);
683
684  mpz_mod_ui(erg, (int_number) from, dst->ch);
685  number r = (number) mpz_get_si(erg);
686
687  mpz_clear(erg);
688  omFree((void *) erg);
689  return (number) r;
690}
691
692/*2
693* convert from an machine long
694*/
695number npMapMachineInt(number from, const coeffs /*src*/,const coeffs dst)
696{
697  long i = (long) (((unsigned long) from) % dst->ch);
698  return (number) i;
699}
700#endif
701
702number npMapCanonicalForm (number a, const coeffs /*src*/, const coeffs dst)
703{
704  setCharacteristic (dst ->ch);
705  CanonicalForm f= CanonicalForm ((InternalCF*)(a));
706  return (number) (f.intval());
707}
708
709nMapFunc npSetMap(const coeffs src, const coeffs dst)
710{
711#ifdef HAVE_RINGS
712  if (nCoeff_is_Ring_2toM(src))
713  {
714    return npMapMachineInt;
715  }
716  if (nCoeff_is_Ring_Z(src) || nCoeff_is_Ring_PtoM(src) || nCoeff_is_Ring_ModN(src))
717  {
718    return npMapGMP;
719  }
720#endif
721  if (nCoeff_is_Q(src))
722  {
723    return nlModP; // npMap0;
724  }
725  if ( nCoeff_is_Zp(src) )
726  {
727    if (n_GetChar(src) == n_GetChar(dst))
728    {
729      return ndCopyMap;
730    }
731    else
732    {
733      return npMapP;
734    }
735  }
736  if (nCoeff_is_long_R(src))
737  {
738    return npMapLongR;
739  }
740  if (nCoeff_is_CF (src))
741  {
742    return npMapCanonicalForm;
743  }
744  return NULL;      /* default */
745}
746
747// -----------------------------------------------------------
748//  operation for very large primes (32003< p < 2^31-1)
749// ----------------------------------------------------------
750#ifdef NV_OPS
751
752number nvMult (number a,number b, const coeffs r)
753{
754  //if (((long)a == 0) || ((long)b == 0))
755  //  return (number)0;
756  //else
757    return nvMultM(a,b,r);
758}
759
760void   nvInpMult(number &a, number b, const coeffs r)
761{
762  number n=nvMultM(a,b,r);
763  a=n;
764}
765
766
767inline long nvInvMod(long a, const coeffs R)
768{
769#ifdef HAVE_DIV_MOD
770  return InvMod(a, R);
771#else
772/// TODO: use "long InvMod(long a, const coeffs R)"?!
773
774   long  s;
775
776   long  u, u0, u1, u2, q, r; // v0, v1, v2,
777
778   u1=1; // v1=0;
779   u2=0; // v2=1;
780   u = a;
781
782   long v = R->ch;
783
784   while (v != 0)
785   {
786      q = u / v;
787      r = u % v;
788      u = v;
789      v = r;
790      u0 = u2;
791//      v0 = v2;
792      u2 = u1 - q*u2;
793//      v2 = v1 - q*v2;
794      u1 = u0;
795//      v1 = v0;
796   }
797
798   s = u1;
799   //t = v1;
800   if (s < 0)
801      return s + R->ch;
802   else
803     return s;
804#endif
805}
806
807inline number nvInversM (number c, const coeffs r)
808{
809  long inv=nvInvMod((long)c,r);
810  return (number)inv;
811}
812
813number nvDiv (number a,number b, const coeffs r)
814{
815  if ((long)a==0)
816    return (number)0;
817  else if ((long)b==0)
818  {
819    WerrorS(nDivBy0);
820    return (number)0;
821  }
822  else
823  {
824    number inv=nvInversM(b,r);
825    return nvMultM(a,inv,r);
826  }
827}
828number  nvInvers (number c, const coeffs r)
829{
830  if ((long)c==0)
831  {
832    WerrorS(nDivBy0);
833    return (number)0;
834  }
835  return nvInversM(c,r);
836}
837void nvPower (number a, int i, number * result, const coeffs r)
838{
839  if (i==0)
840  {
841    //npInit(1,result);
842    *(long *)result = 1;
843  }
844  else if (i==1)
845  {
846    *result = a;
847  }
848  else
849  {
850    nvPower(a,i-1,result,r);
851    *result = nvMultM(a,*result,r);
852  }
853}
854#endif
855
856void    npCoeffWrite  (const coeffs r, BOOLEAN /*details*/)
857{
858  Print("//   characteristic : %d\n",r->ch);
859}
860
Note: See TracBrowser for help on using the repository browser.