source: git/libpolys/coeffs/modulop.cc @ 84bac9

spielwiese
Last change on this file since 84bac9 was 84bac9, checked in by Hans Schoenemann <hannes@…>, 6 years ago
opt: conversion to factory
  • Property mode set to 100644
File size: 16.0 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 const char* npEati(const char *s, int *i, const coeffs r)
267{
268  if (((*s) >= '0') && ((*s) <= '9'))
269  {
270    unsigned long ii=0L;
271    do
272    {
273      ii *= 10;
274      ii += *s++ - '0';
275      if (ii >= (MAX_INT_VAL / 10)) ii = ii % r->ch;
276    }
277    while (((*s) >= '0') && ((*s) <= '9'));
278    if (ii >= (unsigned long)r->ch) ii = ii % r->ch;
279    *i=(int)ii;
280  }
281  else (*i) = 1;
282  return s;
283}
284
285const char * npRead (const char *s, number *a, const coeffs r)
286{
287  int z;
288  int n=1;
289
290  s = npEati(s, &z, r);
291  if ((*s) == '/')
292  {
293    s++;
294    s = npEati(s, &n, r);
295  }
296  if (n == 1)
297    *a = (number)(long)z;
298  else
299  {
300    if ((z==0)&&(n==0)) WerrorS(nDivBy0);
301    else
302    {
303#ifdef NV_OPS
304      if (r->ch>NV_MAX_PRIME)
305        *a = nvDiv((number)(long)z,(number)(long)n,r);
306      else
307#endif
308        *a = npDiv((number)(long)z,(number)(long)n,r);
309    }
310  }
311  n_Test(*a, r);
312  return s;
313}
314
315/*2
316* set the charcteristic (allocate and init tables)
317*/
318
319void npKillChar(coeffs r)
320{
321  #ifdef HAVE_INVTABLE
322  if (r->npInvTable!=NULL)
323  {
324    omFreeSize( (void *)r->npInvTable, r->ch*sizeof(unsigned short) );
325    r->npInvTable=NULL;
326  }
327  #endif
328  #ifndef HAVE_GENERIC_MULT
329  if (r->npExpTable!=NULL)
330  {
331    omFreeSize( (void *)r->npExpTable, r->ch*sizeof(unsigned short) );
332    omFreeSize( (void *)r->npLogTable, r->ch*sizeof(unsigned short) );
333    r->npExpTable=NULL; r->npLogTable=NULL;
334  }
335  #endif
336}
337
338static BOOLEAN npCoeffsEqual(const coeffs r, n_coeffType n, void * parameter)
339{
340  /* test, if r is an instance of nInitCoeffs(n,parameter) */
341  return (n==n_Zp) && (r->ch==(int)(long)parameter);
342}
343CanonicalForm npConvSingNFactoryN( number n, BOOLEAN setChar, const coeffs r )
344{
345  if (setChar) setCharacteristic( r->ch );
346  return CanonicalForm(npInt( n,r ));
347}
348
349number npConvFactoryNSingN( const CanonicalForm n, const coeffs r)
350{
351  if (n.isImm())
352  {
353    return npInit(n.intval(),r);
354  }
355  else
356  {
357    assume(0);
358    return NULL;
359  }
360}
361
362static char* npCoeffName(const coeffs cf)
363{
364  static char npCoeffName_buf[15];
365  snprintf(npCoeffName_buf,14,"ZZ/%d",cf->ch);
366  return npCoeffName_buf;
367}
368
369static char* npCoeffString(const coeffs cf)
370{
371  return omStrDup(npCoeffName(cf));
372}
373
374static void npWriteFd(number n, FILE* f, const coeffs)
375{
376  fprintf(f,"%d ",(int)(long)n);
377}
378
379static number npReadFd(s_buff f, const coeffs)
380{
381  // read int
382  int dd;
383  dd=s_readint(f);
384  return (number)(long)dd;
385}
386
387static number npRandom(siRandProc p, number, number, const coeffs cf)
388{
389  return npInit(p(),cf);
390}
391
392BOOLEAN npInitChar(coeffs r, void* p)
393{
394  assume( getCoeffType(r) == n_Zp );
395  const int c = (int) (long) p;
396
397  assume( c > 0 );
398
399  int i, w;
400
401  r->is_field=TRUE;
402  r->is_domain=TRUE;
403  r->rep=n_rep_int;
404
405  r->ch = c;
406  r->npPminus1M = c /*r->ch*/ - 1;
407
408  //r->cfInitChar=npInitChar;
409  r->cfKillChar=npKillChar;
410  r->nCoeffIsEqual=npCoeffsEqual;
411  r->cfCoeffString=npCoeffString;
412  r->cfCoeffName=npCoeffName;
413  r->cfCoeffWrite=npCoeffWrite;
414
415  r->cfMult  = npMult;
416  r->cfInpMult  = npInpMult;
417  r->cfSub   = npSubM;
418  r->cfAdd   = npAddM;
419  r->cfInpAdd   = npInpAddM;
420  r->cfDiv   = npDiv;
421  r->cfInit = npInit;
422  //r->cfSize  = ndSize;
423  r->cfInt  = npInt;
424  #ifdef HAVE_RINGS
425  //r->cfDivComp = NULL; // only for ring stuff
426  //r->cfIsUnit = NULL; // only for ring stuff
427  //r->cfGetUnit = NULL; // only for ring stuff
428  //r->cfExtGcd = NULL; // only for ring stuff
429  // r->cfDivBy = NULL; // only for ring stuff
430  #endif
431  r->cfInpNeg   = npNeg;
432  r->cfInvers= npInvers;
433  //r->cfCopy  = ndCopy;
434  //r->cfRePart = ndCopy;
435  //r->cfImPart = ndReturn0;
436  r->cfWriteLong = npWrite;
437  r->cfRead = npRead;
438  //r->cfNormalize=ndNormalize;
439  r->cfGreater = npGreater;
440  r->cfEqual = npEqual;
441  r->cfIsZero = npIsZero;
442  r->cfIsOne = npIsOne;
443  r->cfIsMOne = npIsMOne;
444  r->cfGreaterZero = npGreaterZero;
445  //r->cfPower = npPower;
446  //r->cfGetDenom = ndGetDenom;
447  //r->cfGetNumerator = ndGetNumerator;
448  //r->cfGcd  = ndGcd;
449  //r->cfLcm  = ndGcd;
450  //r->cfDelete= ndDelete;
451  r->cfSetMap = npSetMap;
452  //r->cfName = ndName;
453  //r->cfInpMult=ndInpMult;
454  r->convSingNFactoryN=npConvSingNFactoryN;
455  r->convFactoryNSingN=npConvFactoryNSingN;
456  r->cfRandom=npRandom;
457#ifdef LDEBUG
458  // debug stuff
459  r->cfDBTest=npDBTest;
460#endif
461
462  // io via ssi
463  r->cfWriteFd=npWriteFd;
464  r->cfReadFd=npReadFd;
465
466  // the variables:
467  r->type = n_Zp;
468  r->has_simple_Alloc=TRUE;
469  r->has_simple_Inverse=TRUE;
470
471  // the tables
472#ifdef NV_OPS
473  if (r->ch <=NV_MAX_PRIME)
474#endif
475  {
476#ifdef HAVE_INVTABLE
477    r->npInvTable=(unsigned short*)omAlloc0( r->ch*sizeof(unsigned short) );
478#endif
479#ifndef HAVE_GENERIC_MULT
480    r->npExpTable=(unsigned short *)omAlloc0( r->ch*sizeof(unsigned short) );
481    r->npLogTable=(unsigned short *)omAlloc0( r->ch*sizeof(unsigned short) );
482    r->npExpTable[0] = 1;
483    r->npLogTable[0] = 0;
484    if (r->ch > 2)
485    {
486      w = 1;
487      loop
488      {
489        r->npLogTable[1] = 0;
490        w++;
491        i = 0;
492        loop
493        {
494          i++;
495          r->npExpTable[i] =(int)(((long)w * (long)r->npExpTable[i-1]) % r->ch);
496          r->npLogTable[r->npExpTable[i]] = i;
497          if /*(i == r->ch - 1 ) ||*/ (/*(*/ r->npExpTable[i] == 1 /*)*/)
498            break;
499        }
500        if (i == r->ch - 1)
501          break;
502      }
503    }
504    else
505    {
506      r->npExpTable[1] = 1;
507      r->npLogTable[1] = 0;
508    }
509#endif
510  }
511#ifdef NV_OPS
512  else /*if (c>NV_MAX_PRIME)*/
513  {
514    r->cfMult  = nvMult;
515    r->cfDiv   = nvDiv;
516    r->cfExactDiv = nvDiv;
517    r->cfInvers  = nvInvers;
518    r->cfInpMult = nvInpMult;
519    //r->cfPower= nvPower;
520    //if (c>FACTORY_MAX_PRIME) // factory will catch this error
521    //{
522    //  r->convSingNFactoryN=ndConvSingNFactoryN;
523    //}
524  }
525#endif
526  return FALSE;
527}
528
529#ifdef LDEBUG
530BOOLEAN npDBTest (number a, const char *f, const int l, const coeffs r)
531{
532  if (((long)a<0L) || ((long)a>(long)r->ch))
533  {
534    Print("wrong mod p number %ld at %s,%d\n",(long)a,f,l);
535    return FALSE;
536  }
537  return TRUE;
538}
539#endif
540
541static number npMapP(number from, const coeffs src, const coeffs dst_r)
542{
543  long i = (long)from;
544  if (i>src->ch/2)
545  {
546    i-=src->ch;
547    while (i < 0) i+=dst_r->ch;
548  }
549  i%=dst_r->ch;
550  return (number)i;
551}
552
553static number npMapLongR(number from, const coeffs /*src*/, const coeffs dst_r)
554{
555  gmp_float *ff=(gmp_float*)from;
556  mpf_t *f=ff->_mpfp();
557  number res;
558  mpz_ptr dest,ndest;
559  int size,i;
560  int e,al,bl;
561  long iz;
562  mp_ptr qp,dd,nn;
563
564  size = (*f)[0]._mp_size;
565  if (size == 0)
566    return npInit(0,dst_r);
567  if(size<0)
568    size = -size;
569
570  qp = (*f)[0]._mp_d;
571  while(qp[0]==0)
572  {
573    qp++;
574    size--;
575  }
576
577  if(dst_r->ch>2)
578    e=(*f)[0]._mp_exp-size;
579  else
580    e=0;
581  res = ALLOC_RNUMBER();
582#if defined(LDEBUG)
583  res->debug=123456;
584#endif
585  dest = res->z;
586
587  long in=0;
588  if (e<0)
589  {
590    al = dest->_mp_size = size;
591    if (al<2) al = 2;
592    dd = (mp_ptr)omAlloc(sizeof(mp_limb_t)*al);
593    for (i=0;i<size;i++) dd[i] = qp[i];
594    bl = 1-e;
595    nn = (mp_ptr)omAlloc(sizeof(mp_limb_t)*bl);
596    nn[bl-1] = 1;
597    for (i=bl-2;i>=0;i--) nn[i] = 0;
598    ndest = res->n;
599    ndest->_mp_d = nn;
600    ndest->_mp_alloc = ndest->_mp_size = bl;
601    res->s = 0;
602    in=mpz_fdiv_ui(ndest,dst_r->ch);
603    mpz_clear(ndest);
604  }
605  else
606  {
607    al = dest->_mp_size = size+e;
608    if (al<2) al = 2;
609    dd = (mp_ptr)omAlloc(sizeof(mp_limb_t)*al);
610    for (i=0;i<size;i++) dd[i+e] = qp[i];
611    for (i=0;i<e;i++) dd[i] = 0;
612    res->s = 3;
613  }
614
615  dest->_mp_d = dd;
616  dest->_mp_alloc = al;
617  iz=mpz_fdiv_ui(dest,dst_r->ch);
618  mpz_clear(dest);
619  if(res->s==0)
620    iz=(long)npDiv((number)iz,(number)in,dst_r);
621  FREE_RNUMBER(res); // Q!?
622  return (number)iz;
623}
624
625#ifdef HAVE_RINGS
626/*2
627* convert from a GMP integer
628*/
629static number npMapGMP(number from, const coeffs /*src*/, const coeffs dst)
630{
631  mpz_ptr erg = (mpz_ptr) omAlloc(sizeof(mpz_t)); // evtl. spaeter mit bin
632  mpz_init(erg);
633
634  mpz_mod_ui(erg, (mpz_ptr) from, dst->ch);
635  number r = (number) mpz_get_si(erg);
636
637  mpz_clear(erg);
638  omFree((void *) erg);
639  return (number) r;
640}
641
642static number npMapZ(number from, const coeffs src, const coeffs dst)
643{
644  if (SR_HDL(from) & SR_INT)
645  {
646    long f_i=SR_TO_INT(from);
647    return npInit(f_i,dst);
648  }
649  return npMapGMP(from,src,dst);
650}
651
652/*2
653* convert from an machine long
654*/
655static number npMapMachineInt(number from, const coeffs /*src*/,const coeffs dst)
656{
657  long i = (long) (((unsigned long) from) % dst->ch);
658  return (number) i;
659}
660#endif
661
662static number npMapCanonicalForm (number a, const coeffs /*src*/, const coeffs dst)
663{
664  setCharacteristic (dst ->ch);
665  CanonicalForm f= CanonicalForm ((InternalCF*)(a));
666  return (number) (f.intval());
667}
668
669nMapFunc npSetMap(const coeffs src, const coeffs dst)
670{
671#ifdef HAVE_RINGS
672  if ((src->rep==n_rep_int) && nCoeff_is_Ring_2toM(src))
673  {
674    return npMapMachineInt;
675  }
676  if (src->rep==n_rep_gmp) //nCoeff_is_Ring_Z(src) || nCoeff_is_Ring_PtoM(src) || nCoeff_is_Ring_ModN(src))
677  {
678    return npMapGMP;
679  }
680  if (src->rep==n_rep_gap_gmp) //nCoeff_is_Ring_Z(src)
681  {
682    return npMapZ;
683  }
684#endif
685  if (src->rep==n_rep_gap_rat)  /* Q, Z */
686  {
687    return nlModP; // npMap0; // FIXME? TODO? // extern number nlModP(number q, const coeffs Q, const coeffs Zp); // Map q \in QQ \to Zp // FIXME!
688  }
689  if ((src->rep==n_rep_int) &&  nCoeff_is_Zp(src) )
690  {
691    if (n_GetChar(src) == n_GetChar(dst))
692    {
693      return ndCopyMap;
694    }
695    else
696    {
697      return npMapP;
698    }
699  }
700  if ((src->rep==n_rep_gmp_float) && nCoeff_is_long_R(src))
701  {
702    return npMapLongR;
703  }
704  if (nCoeff_is_CF (src))
705  {
706    return npMapCanonicalForm;
707  }
708  return NULL;      /* default */
709}
710
711// -----------------------------------------------------------
712//  operation for very large primes (32749< p < 2^31-1)
713// ----------------------------------------------------------
714#ifdef NV_OPS
715
716number nvMult (number a,number b, const coeffs r)
717{
718  //if (((long)a == 0) || ((long)b == 0))
719  //  return (number)0;
720  //else
721    return nvMultM(a,b,r);
722}
723
724void nvInpMult(number &a, number b, const coeffs r)
725{
726  number n=nvMultM(a,b,r);
727  a=n;
728}
729
730static inline number nvInversM (number c, const coeffs r)
731{
732  long inv=npInvMod((long)c,r);
733  return (number)inv;
734}
735
736number nvDiv (number a,number b, const coeffs r)
737{
738  if ((long)a==0L)
739    return (number)0L;
740  else if ((long)b==0L)
741  {
742    WerrorS(nDivBy0);
743    return (number)0L;
744  }
745  else
746  {
747    number inv=nvInversM(b,r);
748    return nvMultM(a,inv,r);
749  }
750}
751number  nvInvers (number c, const coeffs r)
752{
753  if ((long)c==0L)
754  {
755    WerrorS(nDivBy0);
756    return (number)0L;
757  }
758  return nvInversM(c,r);
759}
760#if 0
761void nvPower (number a, int i, number * result, const coeffs r)
762{
763  if (i==0)
764  {
765    //npInit(1,result);
766    *(long *)result = 1;
767  }
768  else if (i==1)
769  {
770    *result = a;
771  }
772  else
773  {
774    nvPower(a,i-1,result,r);
775    *result = nvMultM(a,*result,r);
776  }
777}
778#endif
779#endif
780
781void    npCoeffWrite  (const coeffs r, BOOLEAN /*details*/)
782{
783  Print("ZZ/%d",r->ch);
784}
785
Note: See TracBrowser for help on using the repository browser.