source: git/coeffs/modulop.cc @ 4d92d7

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