source: git/coeffs/modulop.cc @ 87d61c

spielwiese
Last change on this file since 87d61c was 87d61c, checked in by Hans Schoenemann <hannes@…>, 14 years ago
HAVE_RINGS fixes
  • Property mode set to 100644
File size: 13.5 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 "reporter.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
314static BOOLEAN npCoeffsEqual(const coeffs r, n_coeffType n, void * parameter)
315{
316  /* test, if r is an instance of nInitCoeffs(n,parameter) */
317  return (n==n_Zp) && (r->ch==(int)(long)parameter);
318}
319
320void npInitChar(coeffs r, int c)
321{
322  int i, w;
323
324  r->npPrimeM = c;
325  r->npPminus1M = c /*r->npPrimeM*/ - 1;
326
327  //r->cfInitChar=npInitChar;
328  r->cfKillChar=npKillChar;
329  r->cfSetChar=npSetChar;
330  r->nCoeffIsEqual=npCoeffsEqual;
331
332  r->cfMult  = npMult;
333  r->cfSub   = npSub;
334  r->cfAdd   = npAdd;
335  r->cfDiv   = npDiv;
336  r->cfIntDiv= npDiv;
337  //r->cfIntMod= ndIntMod;
338  r->cfExactDiv= npDiv;
339  r->cfInit = npInit;
340  //r->cfPar = ndPar;
341  //r->cfParDeg = ndParDeg;
342  //r->cfSize  = ndSize;
343  r->cfInt  = npInt;
344  #ifdef HAVE_RINGS
345  //r->cfDivComp = NULL; // only for ring stuff
346  //r->cfIsUnit = NULL; // only for ring stuff
347  //r->cfGetUnit = NULL; // only for ring stuff
348  //r->cfExtGcd = NULL; // only for ring stuff
349  // r->cfDivBy = NULL; // only for ring stuff
350  #endif
351  r->cfNeg   = npNeg;
352  r->cfInvers= npInvers;
353  //r->cfCopy  = ndCopy;
354  //r->cfRePart = ndCopy;
355  //r->cfImPart = ndReturn0;
356  r->cfWrite = npWrite;
357  r->cfRead = npRead;
358  //r->cfNormalize=ndNormalize;
359  r->cfGreater = npGreater;
360  r->cfEqual = npEqual;
361  r->cfIsZero = npIsZero;
362  r->cfIsOne = npIsOne;
363  r->cfIsMOne = npIsMOne;
364  r->cfGreaterZero = npGreaterZero;
365  r->cfPower = npPower;
366  r->cfGetDenom = ndGetDenom;
367  r->cfGetNumerator = ndGetNumerator;
368  //r->cfGcd  = ndGcd;
369  //r->cfLcm  = ndGcd;
370  //r->cfDelete= ndDelete;
371  r->cfSetMap = npSetMap;
372  //r->cfName = ndName;
373  r->cfInpMult=ndInpMult;
374  r->cfInit_bigint= npMap0;
375#ifdef NV_OPS
376  if (c>NV_MAX_PRIME)
377  {
378    r->cfMult  = nvMult;
379    r->cfDiv   = nvDiv;
380    r->cfExactDiv= nvDiv;
381    r->cfInvers= nvInvers;
382    r->cfPower= nvPower;
383  }
384#endif
385#ifdef LDEBUG
386  // debug stuff
387  r->cfDBTest=npDBTest;
388#endif
389 
390  // the variables:
391  r->nNULL = (number)0;
392  //r->type = n_Zp;
393  r->ch = c;
394  r->has_simple_Alloc=TRUE;
395  r->has_simple_Inverse=TRUE;
396
397  // the tables
398#ifdef NV_OPS
399  if (r->npPrimeM <=NV_MAX_PRIME)
400#endif
401  {
402#if !defined(HAVE_DIV_MOD) || !defined(HAVE_MULT_MOD)
403    r->npExpTable=(unsigned short *)omAlloc( r->npPrimeM*sizeof(unsigned short) );
404    r->npLogTable=(unsigned short *)omAlloc( r->npPrimeM*sizeof(unsigned short) );
405    r->npExpTable[0] = 1;
406    r->npLogTable[0] = 0;
407    if (r->npPrimeM > 2)
408    {
409      w = 1;
410      loop
411      {
412        r->npLogTable[1] = 0;
413        w++;
414        i = 0;
415        loop
416        {
417          i++;
418          r->npExpTable[i] =(int)(((long)w * (long)r->npExpTable[i-1])
419                               % r->npPrimeM);
420          r->npLogTable[r->npExpTable[i]] = i;
421          if (/*(i == npPrimeM - 1 ) ||*/ (r->npExpTable[i] == 1))
422            break;
423        }
424        if (i == r->npPrimeM - 1)
425          break;
426      }
427    }
428    else
429    {
430      r->npExpTable[1] = 1;
431      r->npLogTable[1] = 0;
432    }
433#endif
434#ifdef HAVE_DIV_MOD
435    r->npInvTable=(unsigned short*)omAlloc0( r->npPrimeM*sizeof(unsigned short) );
436#endif
437  }
438}
439
440#ifdef LDEBUG
441BOOLEAN npDBTest (number a, const char *f, const int l, const coeffs r)
442{
443  if (((long)a<0) || ((long)a>r->npPrimeM))
444  {
445    Print("wrong mod p number %ld at %s,%d\n",(long)a,f,l);
446    return FALSE;
447  }
448  return TRUE;
449}
450#endif
451
452number npMap0(number from, const coeffs src, const coeffs dst_r)
453{
454  int nlModP(number n, int p, const coeffs r);
455
456  return npInit(nlModP(from, dst_r->npPrimeM, src),dst_r);
457}
458
459number npMapP(number from, const coeffs src, const coeffs dst_r)
460{
461  long i = (long)from;
462  if (i>src->npPrimeM/2)
463  {
464    i-=src->npPrimeM;
465    while (i < 0) i+=dst_r->npPrimeM;
466  }
467  i%=dst_r->npPrimeM;
468  return (number)i;
469}
470
471static number npMapLongR(number from, const coeffs src, const coeffs dst_r)
472{
473  gmp_float *ff=(gmp_float*)from;
474  mpf_t *f=ff->_mpfp();
475  number res;
476  mpz_ptr dest,ndest;
477  int size,i;
478  int e,al,bl,in;
479  long iz;
480  mp_ptr qp,dd,nn;
481
482  size = (*f)[0]._mp_size;
483  if (size == 0)
484    return npInit(0,dst_r);
485  if(size<0)
486    size = -size;
487
488  qp = (*f)[0]._mp_d;
489  while(qp[0]==0)
490  {
491    qp++;
492    size--;
493  }
494
495  if(dst_r->npPrimeM>2)
496    e=(*f)[0]._mp_exp-size;
497  else
498    e=0;
499  res = ALLOC_RNUMBER();
500#if defined(LDEBUG)
501  res->debug=123456;
502#endif
503  dest = res->z;
504
505  if (e<0)
506  {
507    al = dest->_mp_size = size;
508    if (al<2) al = 2;
509    dd = (mp_ptr)omAlloc(sizeof(mp_limb_t)*al);
510    for (i=0;i<size;i++) dd[i] = qp[i];
511    bl = 1-e;
512    nn = (mp_ptr)omAlloc(sizeof(mp_limb_t)*bl);
513    nn[bl-1] = 1;
514    for (i=bl-2;i>=0;i--) nn[i] = 0;
515    ndest = res->n;
516    ndest->_mp_d = nn;
517    ndest->_mp_alloc = ndest->_mp_size = bl;
518    res->s = 0;
519    in=mpz_fdiv_ui(ndest,dst_r->npPrimeM);
520    mpz_clear(ndest);
521  }
522  else
523  {
524    al = dest->_mp_size = size+e;
525    if (al<2) al = 2;
526    dd = (mp_ptr)omAlloc(sizeof(mp_limb_t)*al);
527    for (i=0;i<size;i++) dd[i+e] = qp[i];
528    for (i=0;i<e;i++) dd[i] = 0;
529    res->s = 3;
530  }
531
532  dest->_mp_d = dd;
533  dest->_mp_alloc = al;
534  iz=mpz_fdiv_ui(dest,dst_r->npPrimeM);
535  mpz_clear(dest);
536  if(res->s==0)
537    iz=(long)npDiv((number)iz,(number)in,dst_r);
538  omFreeBin((void *)res, rnumber_bin);
539  return (number)iz;
540}
541
542#ifdef HAVE_RINGS
543/*2
544* convert from a GMP integer
545*/
546number npMapGMP(number from, const coeffs src, const coeffs dst)
547{
548  int_number erg = (int_number) omAlloc(sizeof(mpz_t)); // evtl. spaeter mit bin
549  mpz_init(erg);
550
551  mpz_mod_ui(erg, (int_number) from, dst->npPrimeM);
552  number r = (number) mpz_get_si(erg);
553
554  mpz_clear(erg);
555  omFree((void *) erg);
556  return (number) r;
557}
558
559/*2
560* convert from an machine long
561*/
562number npMapMachineInt(number from, const coeffs src,const coeffs dst)
563{
564  long i = (long) (((unsigned long) from) % dst->npPrimeM);
565  return (number) i;
566}
567#endif
568
569nMapFunc npSetMap(const coeffs src, const coeffs dst)
570{
571#ifdef HAVE_RINGS
572  if (nField_is_Ring_2toM(src))
573  {
574    return npMapMachineInt;
575  }
576  if (nField_is_Ring_Z(src) || nField_is_Ring_PtoM(src) || nField_is_Ring_ModN(src))
577  {
578    return npMapGMP;
579  }
580#endif
581  if (nField_is_Q(src))
582  {
583    return npMap0;
584  }
585  if ( nField_is_Zp(src) )
586  {
587    if (n_GetChar(src) == n_GetChar(dst))
588    {
589      return ndCopyMap;
590    }
591    else
592    {
593      return npMapP;
594    }
595  }
596  if (nField_is_long_R(src))
597  {
598    return npMapLongR;
599  }
600  return NULL;      /* default */
601}
602
603// -----------------------------------------------------------
604//  operation for very large primes (32003< p < 2^31-1)
605// ----------------------------------------------------------
606#ifdef NV_OPS
607
608number nvMult (number a,number b, const coeffs r)
609{
610  //if (((long)a == 0) || ((long)b == 0))
611  //  return (number)0;
612  //else
613    return nvMultM(a,b,r);
614}
615
616void   nvInpMult(number &a, number b, const coeffs r)
617{
618  number n=nvMultM(a,b,r);
619  a=n;
620}
621
622
623long nvInvMod(long a, const coeffs R)
624{
625   long  s, t;
626
627   long  u, v, u0, v0, u1, v1, u2, v2, q, r;
628
629   u1=1; v1=0;
630   u2=0; v2=1;
631   u = a; v = R->npPrimeM;
632
633   while (v != 0)
634   {
635      q = u / v;
636      r = u % v;
637      u = v;
638      v = r;
639      u0 = u2;
640      v0 = v2;
641      u2 =  u1 - q*u2;
642      v2 = v1- q*v2;
643      u1 = u0;
644      v1 = v0;
645   }
646
647   s = u1;
648   //t = v1;
649   if (s < 0)
650      return s + R->npPrimeM;
651   else
652      return s;
653}
654
655inline number nvInversM (number c, const coeffs r)
656{
657  long inv=nvInvMod((long)c,r);
658  return (number)inv;
659}
660
661number nvDiv (number a,number b, const coeffs r)
662{
663  if ((long)a==0)
664    return (number)0;
665  else if ((long)b==0)
666  {
667    WerrorS(nDivBy0);
668    return (number)0;
669  }
670  else
671  {
672    number inv=nvInversM(b,r);
673    return nvMultM(a,inv,r);
674  }
675}
676number  nvInvers (number c, const coeffs r)
677{
678  if ((long)c==0)
679  {
680    WerrorS(nDivBy0);
681    return (number)0;
682  }
683  return nvInversM(c,r);
684}
685void nvPower (number a, int i, number * result, const coeffs r)
686{
687  if (i==0)
688  {
689    //npInit(1,result);
690    *(long *)result = 1;
691  }
692  else if (i==1)
693  {
694    *result = a;
695  }
696  else
697  {
698    nvPower(a,i-1,result,r);
699    *result = nvMultM(a,*result,r);
700  }
701}
702#endif
Note: See TracBrowser for help on using the repository browser.