source: git/libpolys/coeffs/modulop.cc @ 246bbb

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