source: git/libpolys/coeffs/modulop.cc @ 73a9ffb

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