source: git/libpolys/coeffs/modulop.cc @ e5ddd4

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