source: git/libpolys/coeffs/modulop.cc @ 22a09d

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