source: git/kernel/modulop.cc @ ead697

spielwiese
Last change on this file since ead697 was ead697, checked in by Hans Schoenemann <hannes@…>, 12 years ago
tests for tr. 376 git-svn-id: file:///usr/local/Singular/svn/trunk@14402 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 11.5 KB
Line 
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/* $Id$ */
5/*
6* ABSTRACT: numbers modulo p (<=32003)
7*/
8
9#include <string.h>
10#include <kernel/mod2.h>
11#include <omalloc/mylimits.h>
12#include <kernel/structs.h>
13#include <kernel/febase.h>
14#include <omalloc/omalloc.h>
15#include <kernel/numbers.h>
16#include <kernel/longrat.h>
17#include <kernel/mpr_complex.h>
18#include <kernel/ring.h>
19#ifdef HAVE_RINGS
20#include <si_gmp.h>
21#endif
22#include <kernel/modulop.h>
23
24long npPrimeM=0;
25int npGen=0;
26long npPminus1M=0;
27long npMapPrime;
28
29#ifdef HAVE_DIV_MOD
30unsigned short *npInvTable=NULL;
31#endif
32
33#if !defined(HAVE_DIV_MOD) || !defined(HAVE_MULT_MOD)
34unsigned short *npExpTable=NULL;
35unsigned short *npLogTable=NULL;
36#endif
37
38
39BOOLEAN npGreaterZero (number k)
40{
41  int h = (int)((long) k);
42  return ((int)h !=0) && (h <= (npPrimeM>>1));
43}
44
45//unsigned long npMultMod(unsigned long a, unsigned long b)
46//{
47//  unsigned long c = a*b;
48//  c = c % npPrimeM;
49//  assume(c == (unsigned long) npMultM((number) a, (number) b));
50//  return c;
51//}
52
53number npMult (number a,number b)
54{
55  if (((long)a == 0) || ((long)b == 0))
56    return (number)0;
57  else
58    return npMultM(a,b);
59}
60
61/*2
62* create a number from int
63*/
64number npInit (int i, const ring r)
65{
66  long ii=i;
67  while (ii <  0L)                         ii += (long)r->ch;
68  while ((ii>1L) && (ii >= ((long)r->ch))) ii -= (long)r->ch;
69  return (number)ii;
70}
71
72/*2
73* convert a number to int (-p/2 .. p/2)
74*/
75int npInt(number &n, const ring r)
76{
77  if ((long)n > (((long)r->ch) >>1)) return (int)((long)n -((long)r->ch));
78  else                               return (int)((long)n);
79}
80
81number npAdd (number a, number b)
82{
83  return npAddM(a,b);
84}
85
86number npSub (number a, number b)
87{
88  return npSubM(a,b);
89}
90
91BOOLEAN npIsZero (number  a)
92{
93  return 0 == (long)a;
94}
95
96BOOLEAN npIsOne (number a)
97{
98  return 1 == (long)a;
99}
100
101BOOLEAN npIsMOne (number a)
102{
103  return ((npPminus1M == (long)a)&&((long)1!=(long)a));
104}
105
106#ifdef HAVE_DIV_MOD
107#ifdef USE_NTL_XGCD
108//ifdef HAVE_NTL // in ntl.a
109//extern void XGCD(long& d, long& s, long& t, long a, long b);
110#include <NTL/ZZ.h>
111#ifdef NTL_CLIENT
112NTL_CLIENT
113#endif
114#endif
115
116long InvMod(long a)
117{
118   long d, s, t;
119
120#ifdef USE_NTL_XGCD
121   XGCD(d, s, t, a, npPrimeM);
122   assume (d == 1);
123#else
124   long  u, v, u0, v0, u1, v1, u2, v2, q, r;
125
126   assume(a>0);
127   u1=1; u2=0;
128   u = a; v = npPrimeM;
129
130   while (v != 0)
131   {
132      q = u / v;
133      r = u % v;
134      u = v;
135      v = r;
136      u0 = u2;
137      u2 = u1 - q*u2;
138      u1 = u0;
139   }
140
141   assume(u==1);
142   s = u1;
143#endif
144   if (s < 0)
145      return s + npPrimeM;
146   else
147      return s;
148}
149#endif
150
151static inline number npInversM (number c)
152{
153#ifndef HAVE_DIV_MOD
154  return (number)(long)npExpTable[npPminus1M - npLogTable[(long)c]];
155#else
156  long inv=(long)npInvTable[(long)c];
157  if (inv==0)
158  {
159    inv=InvMod((long)c);
160    npInvTable[(long)c]=inv;
161  }
162  return (number)inv;
163#endif
164}
165
166number npDiv (number a,number b)
167{
168//#ifdef NV_OPS
169//  if (npPrimeM>NV_MAX_PRIME)
170//    return nvDiv(a,b);
171//#endif
172  if ((long)a==0)
173    return (number)0;
174#ifndef HAVE_DIV_MOD
175  if ((long)b==0)
176  {
177    WerrorS(nDivBy0);
178    return (number)0;
179  }
180  else
181  {
182    int s = npLogTable[(long)a] - npLogTable[(long)b];
183    if (s < 0)
184      s += npPminus1M;
185    return (number)(long)npExpTable[s];
186  }
187#else
188  number inv=npInversM(b);
189  return npMultM(a,inv);
190#endif
191}
192number  npInvers (number c)
193{
194  if ((long)c==0)
195  {
196    WerrorS("1/0");
197    return (number)0;
198  }
199  return npInversM(c);
200}
201
202number npNeg (number c)
203{
204  if ((long)c==0) return c;
205  return npNegM(c);
206}
207
208BOOLEAN npGreater (number a,number b)
209{
210  //return (long)a != (long)b;
211  return (long)a > (long)b;
212}
213
214BOOLEAN npEqual (number a,number b)
215{
216//  return (long)a == (long)b;
217  return npEqualM(a,b);
218}
219
220void npWrite (number &a, const ring r)
221{
222  if ((long)a>(((long)r->ch) >>1)) StringAppend("-%d",(int)(((long)r->ch)-((long)a)));
223  else                             StringAppend("%d",(int)((long)a));
224}
225
226void npPower (number a, int i, number * result)
227{
228  if (i==0)
229  {
230    //npInit(1,result);
231    *(long *)result = 1;
232  }
233  else if (i==1)
234  {
235    *result = a;
236  }
237  else
238  {
239    npPower(a,i-1,result);
240    *result = npMultM(a,*result);
241  }
242}
243
244static const char* npEati(const char *s, int *i)
245{
246
247  if (((*s) >= '0') && ((*s) <= '9'))
248  {
249    unsigned long ii=0L;
250    do
251    {
252      ii *= 10;
253      ii += *s++ - '0';
254      if (ii >= (MAX_INT_VAL / 10)) ii = ii % npPrimeM;
255    }
256    while (((*s) >= '0') && ((*s) <= '9'));
257    if (ii >= npPrimeM) ii = ii % npPrimeM;
258    *i=(int)ii;
259  }
260  else (*i) = 1;
261  return s;
262}
263
264const char * npRead (const char *s, number *a)
265{
266  int z;
267  int n=1;
268
269  s = npEati(s, &z);
270  if ((*s) == '/')
271  {
272    s++;
273    s = npEati(s, &n);
274  }
275  if (n == 1)
276    *a = (number)z;
277  else
278  {
279    if ((z==0)&&(n==0)) WerrorS(nDivBy0);
280    else
281    {
282#ifdef NV_OPS
283      if (npPrimeM>NV_MAX_PRIME)
284        *a = nvDiv((number)z,(number)n);
285      else
286#endif
287        *a = npDiv((number)z,(number)n);
288    }
289  }
290  return s;
291}
292
293/*2
294* the last used charcteristic
295*/
296//int npGetChar()
297//{
298//  return npPrimeM;
299//}
300
301/*2
302* set the charcteristic (allocate and init tables)
303*/
304
305void npSetChar(int c, ring r)
306{
307
308//  if (c==npPrimeM) return;
309  if ((c>1) || (c<(-1)))
310  {
311    if (c>1) npPrimeM = c;
312    else     npPrimeM = -c;
313    npPminus1M = npPrimeM - 1;
314#ifdef NV_OPS
315    if (r->cf->npPrimeM >NV_MAX_PRIME) return;
316#endif
317#ifdef HAVE_DIV_MOD
318    npInvTable=r->cf->npInvTable;
319#endif
320#if !defined(HAVE_DIV_MOD) || !defined(HAVE_MULT_MOD)
321    npExpTable=r->cf->npExpTable;
322    npLogTable=r->cf->npLogTable;
323    npGen = npExpTable[1];
324#endif
325  }
326  else
327  {
328    npPrimeM=0;
329#ifdef HAVE_DIV_MOD
330    npInvTable=NULL;
331#endif
332#if !defined(HAVE_DIV_MOD) || !defined(HAVE_MULT_MOD)
333    npExpTable=NULL;
334    npLogTable=NULL;
335#endif
336  }
337}
338
339void npInitChar(int c, ring r)
340{
341  int i, w;
342
343  if ((c>1) || (c<(-1)))
344  {
345    if (c>1) r->cf->npPrimeM = c;
346    else     r->cf->npPrimeM = -c;
347    r->cf->npPminus1M = r->cf->npPrimeM - 1;
348#ifdef NV_OPS
349    if (r->cf->npPrimeM <=NV_MAX_PRIME)
350#endif
351    {
352#if !defined(HAVE_DIV_MOD) || !defined(HAVE_MULT_MOD)
353      r->cf->npExpTable=(unsigned short *)omAlloc( r->cf->npPrimeM*sizeof(unsigned short) );
354      r->cf->npLogTable=(unsigned short *)omAlloc( r->cf->npPrimeM*sizeof(unsigned short) );
355      r->cf->npExpTable[0] = 1;
356      r->cf->npLogTable[0] = 0;
357      if (r->cf->npPrimeM > 2)
358      {
359        w = 1;
360        loop
361        {
362          r->cf->npLogTable[1] = 0;
363          w++;
364          i = 0;
365          loop
366          {
367            i++;
368            r->cf->npExpTable[i] =(int)(((long)w * (long)r->cf->npExpTable[i-1])
369                                 % r->cf->npPrimeM);
370            r->cf->npLogTable[r->cf->npExpTable[i]] = i;
371            if (/*(i == npPrimeM - 1 ) ||*/ (r->cf->npExpTable[i] == 1))
372              break;
373          }
374          if (i == r->cf->npPrimeM - 1)
375            break;
376        }
377      }
378      else
379      {
380        r->cf->npExpTable[1] = 1;
381        r->cf->npLogTable[1] = 0;
382      }
383#endif
384#ifdef HAVE_DIV_MOD
385      r->cf->npInvTable=(unsigned short*)omAlloc0( r->cf->npPrimeM*sizeof(unsigned short) );
386#endif
387    }
388  }
389  else
390  {
391    WarnS("nInitChar failed");
392  }
393}
394
395#ifdef LDEBUG
396BOOLEAN npDBTest (number a, const char *f, const int l)
397{
398  if (((long)a<0) || ((long)a>npPrimeM))
399  {
400    Print("wrong mod p number %ld at %s,%d\n",(long)a,f,l);
401    return FALSE;
402  }
403  return TRUE;
404}
405#endif
406
407number npMap0(number from)
408{
409  return npInit(nlModP(from,npPrimeM),currRing);
410}
411
412number npMapP(number from)
413{
414  long i = (long)from;
415  if (i>npMapPrime/2)
416  {
417    i-=npMapPrime;
418    while (i < 0) i+=npPrimeM;
419  }
420  i%=npPrimeM;
421  return (number)i;
422}
423
424static number npMapLongR(number from)
425{
426  gmp_float *ff=(gmp_float*)from;
427  mpf_t *f=ff->_mpfp();
428  number res;
429  mpz_ptr dest,ndest;
430  int size,i;
431  int e,al,bl,in;
432  long iz;
433  mp_ptr qp,dd,nn;
434
435  size = (*f)[0]._mp_size;
436  if (size == 0)
437    return npInit(0,currRing);
438  if(size<0)
439    size = -size;
440
441  qp = (*f)[0]._mp_d;
442  while(qp[0]==0)
443  {
444    qp++;
445    size--;
446  }
447
448  if(npPrimeM>2)
449    e=(*f)[0]._mp_exp-size;
450  else
451    e=0;
452  res = ALLOC_RNUMBER();
453#if defined(LDEBUG)
454  res->debug=123456;
455#endif
456  dest = res->z;
457
458  if (e<0)
459  {
460    al = dest->_mp_size = size;
461    if (al<2) al = 2;
462    dd = (mp_ptr)omAlloc(sizeof(mp_limb_t)*al);
463    for (i=0;i<size;i++) dd[i] = qp[i];
464    bl = 1-e;
465    nn = (mp_ptr)omAlloc(sizeof(mp_limb_t)*bl);
466    nn[bl-1] = 1;
467    for (i=bl-2;i>=0;i--) nn[i] = 0;
468    ndest = res->n;
469    ndest->_mp_d = nn;
470    ndest->_mp_alloc = ndest->_mp_size = bl;
471    res->s = 0;
472    in=mpz_fdiv_ui(ndest,npPrimeM);
473    mpz_clear(ndest);
474  }
475  else
476  {
477    al = dest->_mp_size = size+e;
478    if (al<2) al = 2;
479    dd = (mp_ptr)omAlloc(sizeof(mp_limb_t)*al);
480    for (i=0;i<size;i++) dd[i+e] = qp[i];
481    for (i=0;i<e;i++) dd[i] = 0;
482    res->s = 3;
483  }
484
485  dest->_mp_d = dd;
486  dest->_mp_alloc = al;
487  iz=mpz_fdiv_ui(dest,npPrimeM);
488  mpz_clear(dest);
489  if(res->s==0)
490    iz=(long)npDiv((number)iz,(number)in);
491  FREE_RNUMBER(res);
492  return (number)iz;
493}
494
495#ifdef HAVE_RINGS
496/*2
497* convert from a GMP integer
498*/
499number npMapGMP(number from)
500{
501  int_number erg = (int_number) omAlloc(sizeof(mpz_t)); // evtl. spaeter mit bin
502  mpz_init(erg);
503
504  mpz_mod_ui(erg, (int_number) from, npPrimeM);
505  number r = (number) mpz_get_si(erg);
506
507  mpz_clear(erg);
508  omFree((ADDRESS) erg);
509  return (number) r;
510}
511
512/*2
513* convert from an machine long
514*/
515number npMapMachineInt(number from)
516{
517  long i = (long) (((unsigned long) from) % npPrimeM);
518  return (number) i;
519}
520#endif
521
522nMapFunc npSetMap(const ring src, const ring dst)
523{
524#ifdef HAVE_RINGS
525  if (rField_is_Ring_2toM(src))
526  {
527    return npMapMachineInt;
528  }
529  if (rField_is_Ring_Z(src) || rField_is_Ring_PtoM(src) || rField_is_Ring_ModN(src))
530  {
531    return npMapGMP;
532  }
533#endif
534  if (rField_is_Q(src))
535  {
536    return npMap0;
537  }
538  if ( rField_is_Zp(src) )
539  {
540    if (rChar(src) == rChar(dst))
541    {
542      return ndCopy;
543    }
544    else
545    {
546      npMapPrime=rChar(src);
547      return npMapP;
548    }
549  }
550  if (rField_is_long_R(src))
551  {
552    return npMapLongR;
553  }
554  return NULL;      /* default */
555}
556
557// -----------------------------------------------------------
558//  operation for very large primes (32003< p < 2^31-1)
559// ----------------------------------------------------------
560#ifdef NV_OPS
561
562number nvMult (number a,number b)
563{
564  //if (((long)a == 0) || ((long)b == 0))
565  //  return (number)0;
566  //else
567    return nvMultM(a,b);
568}
569
570void   nvInpMult(number &a, number b, const ring r)
571{
572  number n=nvMultM(a,b);
573  a=n;
574}
575
576
577long nvInvMod(long a)
578{
579   long  s, t;
580
581   long  u, v, u0, v0, u1, v1, u2, v2, q, r;
582
583   u1=1; v1=0;
584   u2=0; v2=1;
585   u = a; v = npPrimeM;
586
587   while (v != 0)
588   {
589      q = u / v;
590      r = u % v;
591      u = v;
592      v = r;
593      u0 = u2;
594      v0 = v2;
595      u2 =  u1 - q*u2;
596      v2 = v1- q*v2;
597      u1 = u0;
598      v1 = v0;
599   }
600
601   s = u1;
602   //t = v1;
603   if (s < 0)
604      return s + npPrimeM;
605   else
606      return s;
607}
608
609static inline number nvInversM (number c)
610{
611  long inv=nvInvMod((long)c);
612  return (number)inv;
613}
614
615number nvDiv (number a,number b)
616{
617  if ((long)a==0)
618    return (number)0;
619  else if ((long)b==0)
620  {
621    WerrorS(nDivBy0);
622    return (number)0;
623  }
624  else
625  {
626    number inv=nvInversM(b);
627    return nvMultM(a,inv);
628  }
629}
630number  nvInvers (number c)
631{
632  if ((long)c==0)
633  {
634    WerrorS(nDivBy0);
635    return (number)0;
636  }
637  return nvInversM(c);
638}
639void nvPower (number a, int i, number * result)
640{
641  if (i==0)
642  {
643    //npInit(1,result);
644    *(long *)result = 1;
645  }
646  else if (i==1)
647  {
648    *result = a;
649  }
650  else
651  {
652    nvPower(a,i-1,result);
653    *result = nvMultM(a,*result);
654  }
655}
656#endif
Note: See TracBrowser for help on using the repository browser.