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

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