source: git/libpolys/coeffs/modulop.cc @ 121fd9

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