source: git/kernel/rmodulo2m.cc @ 04deab

spielwiese
Last change on this file since 04deab was 04deab, checked in by Hans Schönemann <hannes@…>, 14 years ago
ring-indep. stuff for Z/2^n git-svn-id: file:///usr/local/Singular/svn/trunk@12373 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 11.6 KB
Line 
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/* $Id$ */
5/*
6* ABSTRACT: numbers modulo 2^m
7*/
8
9#include <string.h>
10#include "mod2.h"
11
12#ifdef HAVE_RINGS
13#include <mylimits.h>
14#include "structs.h"
15#include "febase.h"
16#include "omalloc.h"
17#include "numbers.h"
18#include "longrat.h"
19#include "mpr_complex.h"
20#include "ring.h"
21#include "rmodulo2m.h"
22#include "si_gmp.h"
23
24int nr2mExp;
25
26/*
27 * Multiply two numbers
28 */
29number nr2mMult (number a,number b)
30{
31  if (((NATNUMBER)a == 0) || ((NATNUMBER)b == 0))
32    return (number)0;
33  else
34    return nr2mMultM(a,b);
35}
36
37/*
38 * Give the smallest non unit k, such that a * x = k = b * y has a solution
39 */
40number nr2mLcm (number a,number b,ring r)
41{
42  NATNUMBER res = 0;
43  if ((NATNUMBER) a == 0) a = (number) 1;
44  if ((NATNUMBER) b == 0) b = (number) 1;
45  while ((NATNUMBER) a % 2 == 0)
46  {
47    a = (number) ((NATNUMBER) a / 2);
48    if ((NATNUMBER) b % 2 == 0) b = (number) ((NATNUMBER) b / 2);
49    res++;
50  }
51  while ((NATNUMBER) b % 2 == 0)
52  {
53    b = (number) ((NATNUMBER) b / 2);
54    res++;
55  }
56  return (number) (1L << res);  // (2**res)
57}
58
59/*
60 * Give the largest non unit k, such that a = x * k, b = y * k has
61 * a solution.
62 */
63number nr2mGcd (number a,number b,ring r)
64{
65  NATNUMBER res = 0;
66  if ((NATNUMBER) a == 0 && (NATNUMBER) b == 0) return (number) 1;
67  while ((NATNUMBER) a % 2 == 0 && (NATNUMBER) b % 2 == 0)
68  {
69    a = (number) ((NATNUMBER) a / 2);
70    b = (number) ((NATNUMBER) b / 2);
71    res++;
72  }
73//  if ((NATNUMBER) b % 2 == 0)
74//  {
75//    return (number) ((1L << res));// * (NATNUMBER) a);  // (2**res)*a    a ist Einheit
76//  }
77//  else
78//  {
79    return (number) ((1L << res));// * (NATNUMBER) b);  // (2**res)*b    b ist Einheit
80//  }
81}
82
83/*
84 * Give the largest non unit k, such that a = x * k, b = y * k has
85 * a solution.
86 */
87number nr2mExtGcd (number a, number b, number *s, number *t)
88{
89  NATNUMBER res = 0;
90  if ((NATNUMBER) a == 0 && (NATNUMBER) b == 0) return (number) 1;
91  while ((NATNUMBER) a % 2 == 0 && (NATNUMBER) b % 2 == 0)
92  {
93    a = (number) ((NATNUMBER) a / 2);
94    b = (number) ((NATNUMBER) b / 2);
95    res++;
96  }
97  if ((NATNUMBER) b % 2 == 0)
98  {
99    *t = NULL;
100    *s = nr2mInvers(a);
101    return (number) ((1L << res));// * (NATNUMBER) a);  // (2**res)*a    a ist Einheit
102  }
103  else
104  {
105    *s = NULL;
106    *t = nr2mInvers(b);
107    return (number) ((1L << res));// * (NATNUMBER) b);  // (2**res)*b    b ist Einheit
108  }
109}
110
111void nr2mPower (number a, int i, number * result)
112{
113  if (i==0)
114  {
115    *(NATNUMBER *)result = 1;
116  }
117  else if (i==1)
118  {
119    *result = a;
120  }
121  else
122  {
123    nr2mPower(a,i-1,result);
124    *result = nr2mMultM(a,*result);
125  }
126}
127
128/*
129 * create a number from int
130 */
131number nr2mInit (int i, const ring r)
132{
133  long ii = i;
134  while (ii < 0) ii += r->nr2mModul ;
135  while ((ii>1) && (ii >= r->nr2mModul )) ii -= r->nr2mModul ;
136  return (number) ii;
137}
138
139/*
140 * convert a number to int (-p/2 .. p/2)
141 */
142int nr2mInt(number &n, const ring r)
143{
144  if ((NATNUMBER)n > (r->nr2mModul  >>1)) return (int)((NATNUMBER)n - r->nr2mModul );
145  else return (int)((NATNUMBER)n);
146}
147
148number nr2mAdd (number a, number b)
149{
150  return nr2mAddM(a,b);
151}
152
153number nr2mSub (number a, number b)
154{
155  return nr2mSubM(a,b);
156}
157
158BOOLEAN nr2mIsUnit (number a)
159{
160  return ((NATNUMBER) a % 2 == 1);
161}
162
163number  nr2mGetUnit (number k)
164{
165  if (k == NULL)
166    return (number) 1;
167  NATNUMBER tmp = (NATNUMBER) k;
168  while (tmp % 2 == 0)
169    tmp = tmp / 2;
170  return (number) tmp;
171}
172
173BOOLEAN nr2mIsZero (number  a)
174{
175  return 0 == (NATNUMBER)a;
176}
177
178BOOLEAN nr2mIsOne (number a)
179{
180  return 1 == (NATNUMBER)a;
181}
182
183BOOLEAN nr2mIsMOne (number a)
184{
185  return (currRing->nr2mModul  == (NATNUMBER)a + 1) 
186        && (currRing->nr2mModul != 2);
187}
188
189BOOLEAN nr2mEqual (number a,number b)
190{
191  return nr2mEqualM(a,b);
192}
193
194BOOLEAN nr2mGreater (number a,number b)
195{
196  return nr2mDivBy(a, b);
197}
198
199BOOLEAN nr2mDivBy (number a,number b)
200{
201  if (a == NULL)
202    return (currRing->nr2mModul  % (NATNUMBER) b) == 0;
203  else
204    return ((NATNUMBER) a % (NATNUMBER) b) == 0;
205  /*
206  if ((NATNUMBER) a == 0) return TRUE;
207  if ((NATNUMBER) b == 0) return FALSE;
208  while ((NATNUMBER) a % 2 == 0 && (NATNUMBER) b % 2 == 0)
209  {
210    a = (number) ((NATNUMBER) a / 2);
211    b = (number) ((NATNUMBER) b / 2);
212}
213  return ((NATNUMBER) b % 2 == 1);
214  */
215}
216
217int nr2mDivComp(number as, number bs)
218{
219  NATNUMBER a = (NATNUMBER) as;
220  NATNUMBER b = (NATNUMBER) bs;
221  assume(a != 0 && b != 0);
222  while (a % 2 == 0 && b % 2 == 0)
223  {
224    a = a / 2;
225    b = b / 2;
226  }
227  if (a % 2 == 0)
228  {
229    return -1;
230  }
231  else
232  {
233    if (b % 2 == 1)
234    {
235      return 0;
236    }
237    else
238    {
239      return 1;
240    }
241  }
242}
243
244BOOLEAN nr2mGreaterZero (number k)
245{
246  return ((NATNUMBER) k !=0) && ((NATNUMBER) k <= (currRing->nr2mModul >>1));
247}
248
249//#ifdef HAVE_DIV_MOD
250#if 1 //ifdef HAVE_NTL // in ntl.a
251//extern void XGCD(long& d, long& s, long& t, long a, long b);
252#include <NTL/ZZ.h>
253#ifdef NTL_CLIENT
254NTL_CLIENT
255#endif
256#else
257void XGCD(long& d, long& s, long& t, long a, long b)
258{
259   long  u, v, u0, v0, u1, v1, u2, v2, q, r;
260
261   long aneg = 0, bneg = 0;
262
263   if (a < 0) {
264      a = -a;
265      aneg = 1;
266   }
267
268   if (b < 0) {
269      b = -b;
270      bneg = 1;
271   }
272
273   u1=1; v1=0;
274   u2=0; v2=1;
275   u = a; v = b;
276
277   while (v != 0) {
278      q = u / v;
279      r = u % v;
280      u = v;
281      v = r;
282      u0 = u2;
283      v0 = v2;
284      u2 =  u1 - q*u2;
285      v2 = v1- q*v2;
286      u1 = u0;
287      v1 = v0;
288   }
289
290   if (aneg)
291      u1 = -u1;
292
293   if (bneg)
294      v1 = -v1;
295
296   d = u;
297   s = u1;
298   t = v1;
299}
300#endif
301
302NATNUMBER InvMod(NATNUMBER a)
303{
304   long d, s, t;
305
306   XGCD(d, s, t, a, currRing->nr2mModul );
307   assume (d == 1);
308   if (s < 0)
309      return s + currRing->nr2mModul ;
310   else
311      return s;
312}
313//#endif
314
315inline number nr2mInversM (number c)
316{
317  // Table !!!
318  NATNUMBER inv;
319  inv = InvMod((NATNUMBER)c);
320  return (number) inv;
321}
322
323number nr2mDiv (number a,number b)
324{
325  if ((NATNUMBER)a==0)
326    return (number)0;
327  else if ((NATNUMBER)b%2==0)
328  {
329    if ((NATNUMBER)b != 0)
330    {
331      while ((NATNUMBER) b%2 == 0 && (NATNUMBER) a%2 == 0)
332      {
333        a = (number) ((NATNUMBER) a / 2);
334        b = (number) ((NATNUMBER) b / 2);
335      }
336    }
337    if ((NATNUMBER) b%2 == 0)
338    {
339      WerrorS("Division not possible, even by cancelling zero divisors.");
340      WerrorS("Result is integer division without remainder.");
341      return (number) ((NATNUMBER) a / (NATNUMBER) b);
342    }
343  }
344  return (number) nr2mMult(a, nr2mInversM(b));
345}
346
347number nr2mMod (number a, number b)
348{
349  /*
350    We need to return the number r which is uniquely determined by the
351    following two properties:
352      (1) 0 <= r < |b| (with respect to '<' and '<=' performed in Z x Z)
353      (2) There exists some k in the integers Z such that a = k * b + r.
354    Consider g := gcd(2^m, |b|). Note that then |b|/g is a unit in Z/2^m.
355    Now, there are three cases:
356      (a) g = 1
357          Then |b| is a unit in Z/2^m, i.e. |b| (and also b) divides a.
358          Thus r = 0.
359      (b) g <> 1 and g divides a
360          Then a = (a/g) * (|b|/g)^(-1) * b (up to sign), i.e. again r = 0.
361      (c) g <> 1 and g does not divide a
362          Let's denote the division with remainder of a by g as follows:
363          a = s * g + t. Then t = a - s * g = a - s * (|b|/g)^(-1) * |b|
364          fulfills (1) and (2), i.e. r := t is the correct result. Hence
365          in this third case, r is the remainder of division of a by g in Z.
366    This algorithm is the same as for the case Z/n, except that we may
367    compute the gcd of |b| and 2^m "by hand": We just extract the highest
368    power of 2 (<= 2^m) that is contained in b.
369  */
370  NATNUMBER g = 1;
371  NATNUMBER b_div = (NATNUMBER)b;
372  if (b_div < 0) b_div = - b_div; // b_div now represents |b|
373  NATNUMBER r = 0;
374  while ((g < currRing->nr2mModul ) && (b_div > 0) && (b_div % 2 == 0))
375  {
376    b_div = b_div >> 1;
377    g = g << 1;
378  } // g is now the gcd of 2^m and |b|
379
380  if (g != 1) r = (NATNUMBER)a % g;
381  return (number)r;
382}
383
384number nr2mIntDiv (number a,number b)
385{
386  if ((NATNUMBER)a==0)
387  {
388    if ((NATNUMBER)b==0)
389      return (number) 1;
390    if ((NATNUMBER)b==1)
391      return (number) 0;
392    return (number) (currRing->nr2mModul  / (NATNUMBER) b);
393  }
394  else
395  {
396    if ((NATNUMBER)b==0)
397      return (number) 0;
398    return (number) ((NATNUMBER) a / (NATNUMBER) b);
399  }
400}
401
402number  nr2mInvers (number c)
403{
404  if ((NATNUMBER)c%2==0)
405  {
406    WerrorS("division by zero divisor");
407    return (number)0;
408  }
409  return nr2mInversM(c);
410}
411
412number nr2mNeg (number c)
413{
414  if ((NATNUMBER)c==0) return c;
415  return nr2mNegM(c);
416}
417
418number nr2mMapMachineInt(number from)
419{
420  NATNUMBER i = ((NATNUMBER) from) % currRing->nr2mModul ;
421  return (number) i;
422}
423
424number nr2mMapZp(number from)
425{
426  long ii = (long) from;
427  while (ii < 0) ii += currRing->nr2mModul ;
428  while ((ii>1) && (ii >= currRing->nr2mModul )) ii -= currRing->nr2mModul ;
429  return (number) ii;
430}
431
432number nr2mMapQ(number from)
433{
434  int_number erg = (int_number) omAlloc(sizeof(MP_INT)); // evtl. spaeter mit bin
435  mpz_init(erg);
436
437  nlGMP(from, (number) erg);
438  mpz_mod_ui(erg, erg, currRing->nr2mModul );
439  number r = (number) mpz_get_ui(erg);
440
441  mpz_clear(erg);
442  omFree((ADDRESS) erg);
443  return (number) r;
444}
445
446number nr2mMapGMP(number from)
447{
448  int_number erg = (int_number) omAlloc(sizeof(MP_INT)); // evtl. spaeter mit bin
449  mpz_init(erg);
450
451  mpz_mod_ui(erg, (int_number) from, currRing->nr2mModul );
452  number r = (number) mpz_get_ui(erg);
453
454  mpz_clear(erg);
455  omFree((ADDRESS) erg);
456  return (number) r;
457}
458
459nMapFunc nr2mSetMap(ring src, ring dst)
460{
461  if (rField_is_Ring_2toM(src)
462     && (src->ringflagb >= dst->ringflagb))
463  {
464    return nr2mMapMachineInt;
465  }
466  if (rField_is_Ring_Z(src))
467  {
468    return nr2mMapGMP;
469  }
470  if (rField_is_Q(src))
471  {
472    return nr2mMapQ;
473  }
474  if (rField_is_Zp(src)
475     && (src->ch == 2)
476     && (dst->ringflagb == 1))
477  {
478    return nr2mMapZp;
479  }
480  if (rField_is_Ring_PtoM(src) || rField_is_Ring_ModN(src))
481  {
482    // Computing the n of Z/n
483    int_number modul = (int_number) omAlloc(sizeof(MP_INT)); // evtl. spaeter mit bin
484    mpz_init(modul);
485    mpz_set(modul, src->ringflaga);
486    mpz_pow_ui(modul, modul, src->ringflagb);
487    if (mpz_divisible_2exp_p(modul, dst->ringflagb))
488    {
489      mpz_clear(modul);
490      omFree((ADDRESS) modul);
491      return nr2mMapGMP;
492    }
493    mpz_clear(modul);
494    omFree((ADDRESS) modul);
495  }
496  return NULL;      // default
497}
498
499/*
500 * set the exponent (allocate and init tables) (TODO)
501 */
502
503void nr2mSetExp(int m, const ring r)
504{
505  if (m>1)
506  {
507    nr2mExp = m;
508    r->nr2mModul  = 2;
509    for (int i = 1; i < m; i++)
510    {
511      r->nr2mModul  = r->nr2mModul  * 2;
512    }
513  }
514  else
515  {
516    nr2mExp=2;
517    r->nr2mModul =4;
518  }
519}
520
521void nr2mInitExp(int m, const ring r)
522{
523  nr2mSetExp(m, r);
524  if (m<2) WarnS("nInitExp failed: using Z/2^2");
525}
526
527#ifdef LDEBUG
528BOOLEAN nr2mDBTest (number a, const char *f, const int l)
529{
530  if (((NATNUMBER)a<0) || ((NATNUMBER)a>currRing->nr2mModul ))
531  {
532    return FALSE;
533  }
534  return TRUE;
535}
536#endif
537
538void nr2mWrite (number &a)
539{
540  ring r=currRing;
541  if ((NATNUMBER)a > (r->nr2mModul  >>1))
542     StringAppend("-%d",(int)(r->nr2mModul -((NATNUMBER)a)));
543  else                          StringAppend("%d",(int)((NATNUMBER)a));
544}
545
546static const char* nr2mEati(const char *s, int *i)
547{
548
549  if (((*s) >= '0') && ((*s) <= '9'))
550  {
551    (*i) = 0;
552    do
553    {
554      (*i) *= 10;
555      (*i) += *s++ - '0';
556      if ((*i) >= (MAX_INT_VAL / 10)) (*i) = (*i) % currRing->nr2mModul ;
557    }
558    while (((*s) >= '0') && ((*s) <= '9'));
559    (*i) = (*i) % currRing->nr2mModul ;
560  }
561  else (*i) = 1;
562  return s;
563}
564
565const char * nr2mRead (const char *s, number *a)
566{
567  int z;
568  int n=1;
569
570  s = nr2mEati(s, &z);
571  if ((*s) == '/')
572  {
573    s++;
574    s = nr2mEati(s, &n);
575  }
576  if (n == 1)
577    *a = (number)z;
578  else
579      *a = nr2mDiv((number)z,(number)n);
580  return s;
581}
582#endif
Note: See TracBrowser for help on using the repository browser.