source: git/kernel/modulop.cc @ 0f7420d

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