source: git/kernel/modulop.cc @ f2f460

spielwiese
Last change on this file since f2f460 was 6c15ec, checked in by Hans Schönemann <hannes@…>, 17 years ago
*hannes: map rationals to large prime fields git-svn-id: file:///usr/local/Singular/svn/trunk@9507 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 10.0 KB
Line 
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/* $Id: modulop.cc,v 1.7 2006-11-21 11:00:56 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("div by 0");
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
241char* npEati(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
260char * npRead (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, char *f, int l)
387{
388  if (((long)a<0) || ((long)a>npPrimeM))
389  {
390    return FALSE;
391  }
392  return TRUE;
393}
394#endif
395
396number npMap0(number from)
397{
398  return npInit(nlModP(from,npPrimeM));
399}
400
401number npMapP(number from)
402{
403  long i = (long)from;
404  if (i>npMapPrime/2)
405  {
406    i-=npMapPrime;
407    while (i < 0) i+=npPrimeM;
408  }
409  i%=npPrimeM;
410  return (number)i;
411}
412
413static number npMapLongR(number from)
414{
415  gmp_float *ff=(gmp_float*)from;
416  mpf_t *f=ff->_mpfp();
417  number res;
418  lint *dest,*ndest;
419  int size,i;
420  int e,al,bl,in;
421  long iz;
422  mp_ptr qp,dd,nn;
423
424  size = (*f)[0]._mp_size;
425  if (size == 0)
426    return npInit(0);
427  if(size<0)
428    size = -size;
429
430  qp = (*f)[0]._mp_d;
431  while(qp[0]==0)
432  {
433    qp++;
434    size--;
435  }
436
437  if(npPrimeM>2)
438    e=(*f)[0]._mp_exp-size;
439  else
440    e=0;
441  res = (number)omAllocBin(rnumber_bin);
442#if defined(LDEBUG)
443  res->debug=123456;
444#endif
445  dest = &(res->z);
446
447  if (e<0)
448  {
449    al = dest->_mp_size = size;
450    if (al<2) al = 2;
451    dd = (mp_ptr)omAlloc(sizeof(mp_limb_t)*al);
452    for (i=0;i<size;i++) dd[i] = qp[i];
453    bl = 1-e;
454    nn = (mp_ptr)omAlloc(sizeof(mp_limb_t)*bl);
455    nn[bl-1] = 1;
456    for (i=bl-2;i>=0;i--) nn[i] = 0;
457    ndest = &(res->n);
458    ndest->_mp_d = nn;
459    ndest->_mp_alloc = ndest->_mp_size = bl;
460    res->s = 0;
461    in=mpz_mmod_ui(NULL,ndest,npPrimeM);
462    mpz_clear(ndest);
463  }
464  else
465  {
466    al = dest->_mp_size = size+e;
467    if (al<2) al = 2;
468    dd = (mp_ptr)omAlloc(sizeof(mp_limb_t)*al);
469    for (i=0;i<size;i++) dd[i+e] = qp[i];
470    for (i=0;i<e;i++) dd[i] = 0;
471    res->s = 3;
472  }
473
474  dest->_mp_d = dd;
475  dest->_mp_alloc = al;
476  iz=mpz_mmod_ui(NULL,dest,npPrimeM);
477  mpz_clear(dest);
478  omFreeBin((ADDRESS)res, rnumber_bin);
479  if(res->s==0)
480    iz=(long)npDiv((number)iz,(number)in);
481  return (number)iz;
482}
483
484nMapFunc npSetMap(ring src, ring dst)
485{
486  if (rField_is_Q(src))
487  {
488    return npMap0;
489  }
490  if ( rField_is_Zp(src) )
491  {
492    if (rChar(src) == rChar(dst))
493    {
494      return ndCopy;
495    }
496    else
497    {
498      npMapPrime=rChar(src);
499      return npMapP;
500    }
501  }
502  if (rField_is_long_R(src))
503  {
504    return npMapLongR;
505  }
506  return NULL;      /* default */
507}
508
509// -----------------------------------------------------------
510//  operation for very large primes (32003< p < 2^31-1)
511// ----------------------------------------------------------
512#ifdef NV_OPS
513
514number nvMult (number a,number b)
515{
516  if (((long)a == 0) || ((long)b == 0))
517    return (number)0;
518  else
519    return nvMultM(a,b);
520}
521
522long nvInvMod(long a)
523{
524   long  s, t;
525
526   long  u, v, u0, v0, u1, v1, u2, v2, q, r;
527
528   u1=1; v1=0;
529   u2=0; v2=1;
530   u = a; v = npPrimeM;
531
532   while (v != 0) {
533      q = u / v;
534      r = u % v;
535      u = v;
536      v = r;
537      u0 = u2;
538      v0 = v2;
539      u2 =  u1 - q*u2;
540      v2 = v1- q*v2;
541      u1 = u0;
542      v1 = v0;
543   }
544
545   s = u1;
546   //t = v1;
547   if (s < 0)
548      return s + npPrimeM;
549   else
550      return s;
551}
552
553inline number nvInversM (number c)
554{
555  long inv=nvInvMod((long)c);
556  return (number)inv;
557}
558
559number nvDiv (number a,number b)
560{
561  if ((long)a==0)
562    return (number)0;
563  else if ((long)b==0)
564  {
565    WerrorS("div by 0");
566    return (number)0;
567  }
568  else
569  {
570    number inv=nvInversM(b);
571    return nvMultM(a,inv);
572  }
573}
574number  nvInvers (number c)
575{
576  if ((long)c==0)
577  {
578    WerrorS("1/0");
579    return (number)0;
580  }
581  return nvInversM(c);
582}
583#endif
Note: See TracBrowser for help on using the repository browser.