source: git/kernel/modulop.cc @ e7c6b22

spielwiese
Last change on this file since e7c6b22 was c81a40, checked in by Oliver Wienand <wienand@…>, 16 years ago
Maps für Bigint Modul bei Z/m wird nun als GMP gespeichert git-svn-id: file:///usr/local/Singular/svn/trunk@10870 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 10.9 KB
Line 
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/* $Id: modulop.cc,v 1.12 2008-07-16 12:41:33 wienand 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#ifdef HAVE_RINGS
20#include <gmp.h>
21#endif
22#include "modulop.h"
23
24long npPrimeM=0;
25int npGen=0;
26long npPminus1M=0;
27long npMapPrime;
28
29#ifdef HAVE_DIV_MOD
30CARDINAL *npInvTable=NULL;
31#endif
32
33#if !defined(HAVE_DIV_MOD) || !defined(HAVE_MULT_MOD)
34CARDINAL *npExpTable=NULL;
35CARDINAL *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)
65{
66  long ii=i;
67  while (ii <  0)                    ii += npPrimeM;
68  while ((ii>1) && (ii >= npPrimeM)) ii -= npPrimeM;
69  return (number)ii;
70}
71
72/*2
73* convert a number to int (-p/2 .. p/2)
74*/
75int npInt(number &n)
76{
77  if ((long)n > (npPrimeM >>1)) return (int)((long)n -npPrimeM);
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
151inline number npInversM (number c)
152{
153#ifndef HAVE_DIV_MOD
154  return (number)npExpTable[npPminus1M - npLogTable[(long)c]];
155#else
156  long inv=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)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)
221{
222  if ((long)a > (npPrimeM >>1)) StringAppend("-%d",(int)(npPrimeM-((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    (*i) = 0;
250    do
251    {
252      (*i) *= 10;
253      (*i) += *s++ - '0';
254      if ((*i) >= (MAX_INT_VAL / 10)) (*i) = (*i) % npPrimeM;
255    }
256    while (((*s) >= '0') && ((*s) <= '9'));
257    if ((*i) >= npPrimeM) (*i) = (*i) % npPrimeM;
258  }
259  else (*i) = 1;
260  return s;
261}
262
263const char * npRead (const char *s, number *a)
264{
265  int z;
266  int n=1;
267
268  s = npEati(s, &z);
269  if ((*s) == '/')
270  {
271    s++;
272    s = npEati(s, &n);
273  }
274  if (n == 1)
275    *a = (number)z;
276  else
277#ifdef NV_OPS
278    if (npPrimeM>NV_MAX_PRIME)
279      *a = nvDiv((number)z,(number)n);
280    else
281#endif
282      *a = npDiv((number)z,(number)n);
283  return s;
284}
285
286/*2
287* the last used charcteristic
288*/
289//int npGetChar()
290//{
291//  return npPrimeM;
292//}
293
294/*2
295* set the charcteristic (allocate and init tables)
296*/
297
298void npSetChar(int c, ring r)
299{
300
301//  if (c==npPrimeM) return;
302  if ((c>1) || (c<(-1)))
303  {
304    if (c>1) npPrimeM = c;
305    else     npPrimeM = -c;
306    npPminus1M = npPrimeM - 1;
307#ifdef NV_OPS
308    if (r->cf->npPrimeM >NV_MAX_PRIME) return;
309#endif
310#ifdef HAVE_DIV_MOD
311    npInvTable=r->cf->npInvTable;
312#endif
313#if !defined(HAVE_DIV_MOD) || !defined(HAVE_MULT_MOD)
314    npExpTable=r->cf->npExpTable;
315    npLogTable=r->cf->npLogTable;
316    npGen = npExpTable[1];
317#endif
318  }
319  else
320  {
321    npPrimeM=0;
322#ifdef HAVE_DIV_MOD
323    npInvTable=NULL;
324#endif
325#if !defined(HAVE_DIV_MOD) || !defined(HAVE_MULT_MOD)
326    npExpTable=NULL;
327    npLogTable=NULL;
328#endif
329  }
330}
331
332void npInitChar(int c, ring r)
333{
334  int i, w;
335
336  if ((c>1) || (c<(-1)))
337  {
338    if (c>1) r->cf->npPrimeM = c;
339    else     r->cf->npPrimeM = -c;
340    r->cf->npPminus1M = r->cf->npPrimeM - 1;
341#ifdef NV_OPS
342    if (r->cf->npPrimeM <=NV_MAX_PRIME)
343#endif
344    {
345#if !defined(HAVE_DIV_MOD) || !defined(HAVE_MULT_MOD)
346      r->cf->npExpTable=(CARDINAL *)omAlloc( r->cf->npPrimeM*sizeof(CARDINAL) );
347      r->cf->npLogTable=(CARDINAL *)omAlloc( r->cf->npPrimeM*sizeof(CARDINAL) );
348      r->cf->npExpTable[0] = 1;
349      r->cf->npLogTable[0] = 0;
350      if (r->cf->npPrimeM > 2)
351      {
352        w = 1;
353        loop
354        {
355          r->cf->npLogTable[1] = 0;
356          w++;
357          i = 0;
358          loop
359          {
360            i++;
361            r->cf->npExpTable[i] =(int)(((long)w * (long)r->cf->npExpTable[i-1])
362                                 % r->cf->npPrimeM);
363            r->cf->npLogTable[r->cf->npExpTable[i]] = i;
364            if (/*(i == npPrimeM - 1 ) ||*/ (r->cf->npExpTable[i] == 1))
365              break;
366          }
367          if (i == r->cf->npPrimeM - 1)
368            break;
369        }
370      }
371      else
372      {
373        r->cf->npExpTable[1] = 1;
374        r->cf->npLogTable[1] = 0;
375      }
376#endif
377#ifdef HAVE_DIV_MOD
378      r->cf->npInvTable=(CARDINAL*)omAlloc0( r->cf->npPrimeM*sizeof(CARDINAL) );
379#endif
380    }
381  }
382  else
383  {
384    WarnS("nInitChar failed");
385  }
386}
387
388#ifdef LDEBUG
389BOOLEAN npDBTest (number a, const char *f, const int l)
390{
391  if (((long)a<0) || ((long)a>npPrimeM))
392  {
393    Print("wrong mod p number %ld at %s,%d\n",(long)a,f,l);
394    return FALSE;
395  }
396  return TRUE;
397}
398#endif
399
400number npMap0(number from)
401{
402  return npInit(nlModP(from,npPrimeM));
403}
404
405number npMapP(number from)
406{
407  long i = (long)from;
408  if (i>npMapPrime/2)
409  {
410    i-=npMapPrime;
411    while (i < 0) i+=npPrimeM;
412  }
413  i%=npPrimeM;
414  return (number)i;
415}
416
417static number npMapLongR(number from)
418{
419  gmp_float *ff=(gmp_float*)from;
420  mpf_t *f=ff->_mpfp();
421  number res;
422  lint *dest,*ndest;
423  int size,i;
424  int e,al,bl,in;
425  long iz;
426  mp_ptr qp,dd,nn;
427
428  size = (*f)[0]._mp_size;
429  if (size == 0)
430    return npInit(0);
431  if(size<0)
432    size = -size;
433
434  qp = (*f)[0]._mp_d;
435  while(qp[0]==0)
436  {
437    qp++;
438    size--;
439  }
440
441  if(npPrimeM>2)
442    e=(*f)[0]._mp_exp-size;
443  else
444    e=0;
445  res = (number)omAllocBin(rnumber_bin);
446#if defined(LDEBUG)
447  res->debug=123456;
448#endif
449  dest = &(res->z);
450
451  if (e<0)
452  {
453    al = dest->_mp_size = size;
454    if (al<2) al = 2;
455    dd = (mp_ptr)omAlloc(sizeof(mp_limb_t)*al);
456    for (i=0;i<size;i++) dd[i] = qp[i];
457    bl = 1-e;
458    nn = (mp_ptr)omAlloc(sizeof(mp_limb_t)*bl);
459    nn[bl-1] = 1;
460    for (i=bl-2;i>=0;i--) nn[i] = 0;
461    ndest = &(res->n);
462    ndest->_mp_d = nn;
463    ndest->_mp_alloc = ndest->_mp_size = bl;
464    res->s = 0;
465    in=mpz_mmod_ui(NULL,ndest,npPrimeM);
466    mpz_clear(ndest);
467  }
468  else
469  {
470    al = dest->_mp_size = size+e;
471    if (al<2) al = 2;
472    dd = (mp_ptr)omAlloc(sizeof(mp_limb_t)*al);
473    for (i=0;i<size;i++) dd[i+e] = qp[i];
474    for (i=0;i<e;i++) dd[i] = 0;
475    res->s = 3;
476  }
477
478  dest->_mp_d = dd;
479  dest->_mp_alloc = al;
480  iz=mpz_mmod_ui(NULL,dest,npPrimeM);
481  mpz_clear(dest);
482  omFreeBin((ADDRESS)res, rnumber_bin);
483  if(res->s==0)
484    iz=(long)npDiv((number)iz,(number)in);
485  return (number)iz;
486}
487
488#ifdef HAVE_RINGS
489/*2
490* convert from a GMP integer
491*/
492number npMapGMP(number from)
493{
494  int_number erg = (int_number) omAlloc(sizeof(MP_INT)); // evtl. spaeter mit bin
495  mpz_init(erg);
496
497  mpz_mod_ui(erg, (int_number) from, npPrimeM);
498  number r = (number) mpz_get_si(erg);
499
500  mpz_clear(erg);
501  omFree((ADDRESS) erg);
502  return (number) r;
503}
504
505/*2
506* convert from an machine long
507*/
508number npMapMachineInt(number from)
509{
510  long i = (long) (((unsigned long) from) % npPrimeM);
511  return (number) i;
512}
513#endif
514
515nMapFunc npSetMap(ring src, ring dst)
516{
517#ifdef HAVE_RINGS
518  if (rField_is_Ring_2toM(src))
519  {
520    return npMapMachineInt;
521  }
522  if (rField_is_Ring_Z(src) || rField_is_Ring_PtoM(src) || rField_is_Ring_ModN(src))
523  {
524    return npMapGMP;
525  }
526#endif
527  if (rField_is_Q(src))
528  {
529    return npMap0;
530  }
531  if ( rField_is_Zp(src) )
532  {
533    if (rChar(src) == rChar(dst))
534    {
535      return ndCopy;
536    }
537    else
538    {
539      npMapPrime=rChar(src);
540      return npMapP;
541    }
542  }
543  if (rField_is_long_R(src))
544  {
545    return npMapLongR;
546  }
547  return NULL;      /* default */
548}
549
550// -----------------------------------------------------------
551//  operation for very large primes (32003< p < 2^31-1)
552// ----------------------------------------------------------
553#ifdef NV_OPS
554
555number nvMult (number a,number b)
556{
557  if (((long)a == 0) || ((long)b == 0))
558    return (number)0;
559  else
560    return nvMultM(a,b);
561}
562
563long nvInvMod(long a)
564{
565   long  s, t;
566
567   long  u, v, u0, v0, u1, v1, u2, v2, q, r;
568
569   u1=1; v1=0;
570   u2=0; v2=1;
571   u = a; v = npPrimeM;
572
573   while (v != 0) {
574      q = u / v;
575      r = u % v;
576      u = v;
577      v = r;
578      u0 = u2;
579      v0 = v2;
580      u2 =  u1 - q*u2;
581      v2 = v1- q*v2;
582      u1 = u0;
583      v1 = v0;
584   }
585
586   s = u1;
587   //t = v1;
588   if (s < 0)
589      return s + npPrimeM;
590   else
591      return s;
592}
593
594inline number nvInversM (number c)
595{
596  long inv=nvInvMod((long)c);
597  return (number)inv;
598}
599
600number nvDiv (number a,number b)
601{
602  if ((long)a==0)
603    return (number)0;
604  else if ((long)b==0)
605  {
606    WerrorS(nDivBy0);
607    return (number)0;
608  }
609  else
610  {
611    number inv=nvInversM(b);
612    return nvMultM(a,inv);
613  }
614}
615number  nvInvers (number c)
616{
617  if ((long)c==0)
618  {
619    WerrorS(nDivBy0);
620    return (number)0;
621  }
622  return nvInversM(c);
623}
624#endif
Note: See TracBrowser for help on using the repository browser.