source: git/libpolys/coeffs/rmodulo2m.cc @ e25a99

spielwiese
Last change on this file since e25a99 was e25a99, checked in by Oleksandr Motsak <motsak@…>, 13 years ago
FIX: rename 'ringflagb' into 'mod2mMask' for rings (Z/2m)
  • Property mode set to 100644
File size: 16.7 KB
Line 
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/* $Id$ */
5/*
6* ABSTRACT: numbers modulo 2^m
7*/
8
9#include "config.h"
10#include <misc/auxiliary.h>
11
12#ifdef HAVE_RINGS
13
14#include <misc/mylimits.h>
15#include <coeffs/coeffs.h>
16#include <reporter/reporter.h>
17#include <omalloc/omalloc.h>
18#include <coeffs/numbers.h>
19#include <coeffs/longrat.h>
20#include <coeffs/mpr_complex.h>
21#include <coeffs/rmodulo2m.h>
22#include <coeffs/si_gmp.h>
23
24#include <string.h>
25
26extern omBin gmp_nrz_bin; /* init in rintegers*/
27
28void    nr2mCoeffWrite  (const coeffs r)
29{
30  Print("//   Z/2^%lu\n", r->modExponent); 
31}
32
33/* for initializing function pointers */
34BOOLEAN nr2mInitChar (coeffs r, void* p)
35{
36 
37  nr2mInitExp((int)(long)(p), r);
38
39  r->cfInit        = nr2mInit;
40  r->cfCopy        = ndCopy;
41  r->cfInt         = nr2mInt;
42  r->cfAdd         = nr2mAdd;
43  r->cfSub         = nr2mSub;
44  r->cfMult        = nr2mMult;
45  r->cfDiv         = nr2mDiv;
46  r->cfIntDiv      = nr2mIntDiv;
47  r->cfIntMod      = nr2mMod;
48  r->cfExactDiv    = nr2mDiv;
49  r->cfNeg         = nr2mNeg;
50  r->cfInvers      = nr2mInvers;
51  r->cfDivBy       = nr2mDivBy;
52  r->cfDivComp     = nr2mDivComp;
53  r->cfGreater     = nr2mGreater;
54  r->cfEqual       = nr2mEqual;
55  r->cfIsZero      = nr2mIsZero;
56  r->cfIsOne       = nr2mIsOne;
57  r->cfIsMOne      = nr2mIsMOne;
58  r->cfGreaterZero = nr2mGreaterZero;
59  r->cfWrite       = nr2mWrite;
60  r->cfRead        = nr2mRead;
61  r->cfPower       = nr2mPower;
62  r->cfSetMap      = nr2mSetMap;
63  r->cfNormalize   = ndNormalize;
64  r->cfLcm         = nr2mLcm;
65  r->cfGcd         = nr2mGcd;
66  r->cfIsUnit      = nr2mIsUnit;
67  r->cfGetUnit     = nr2mGetUnit;
68  r->cfExtGcd      = nr2mExtGcd;
69  r->cfName        = ndName;
70  r->cfCoeffWrite  = nr2mCoeffWrite;
71#ifdef LDEBUG
72  r->cfDBTest      = nr2mDBTest;
73#endif
74  r->has_simple_Alloc=TRUE;
75  return FALSE;
76}
77
78/*
79 * Multiply two numbers
80 */
81number nr2mMult(number a, number b, const coeffs r)
82{
83  if (((NATNUMBER)a == 0) || ((NATNUMBER)b == 0))
84    return (number)0;
85  else
86    return nr2mMultM(a, b, r);
87}
88
89/*
90 * Give the smallest k, such that a * x = k = b * y has a solution
91 */
92number nr2mLcm(number a, number b, const coeffs r)
93{
94  NATNUMBER res = 0;
95  if ((NATNUMBER)a == 0) a = (number) 1;
96  if ((NATNUMBER)b == 0) b = (number) 1;
97  while ((NATNUMBER)a % 2 == 0)
98  {
99    a = (number)((NATNUMBER)a / 2);
100    if ((NATNUMBER)b % 2 == 0) b = (number)((NATNUMBER)b / 2);
101    res++;
102  }
103  while ((NATNUMBER)b % 2 == 0)
104  {
105    b = (number)((NATNUMBER)b / 2);
106    res++;
107  }
108  return (number)(1L << res);  // (2**res)
109}
110
111/*
112 * Give the largest k, such that a = x * k, b = y * k has
113 * a solution.
114 */
115number nr2mGcd(number a, number b, const coeffs r)
116{
117  NATNUMBER res = 0;
118  if ((NATNUMBER)a == 0 && (NATNUMBER)b == 0) return (number)1;
119  while ((NATNUMBER)a % 2 == 0 && (NATNUMBER)b % 2 == 0)
120  {
121    a = (number)((NATNUMBER)a / 2);
122    b = (number)((NATNUMBER)b / 2);
123    res++;
124  }
125//  if ((NATNUMBER)b % 2 == 0)
126//  {
127//    return (number)((1L << res)); // * (NATNUMBER) a);  // (2**res)*a    a is a unit
128//  }
129//  else
130//  {
131    return (number)((1L << res)); // * (NATNUMBER) b);  // (2**res)*b    b is a unit
132//  }
133}
134
135/*
136 * Give the largest k, such that a = x * k, b = y * k has
137 * a solution.
138 */
139number nr2mExtGcd(number a, number b, number *s, number *t, const coeffs r)
140{
141  NATNUMBER res = 0;
142  if ((NATNUMBER)a == 0 && (NATNUMBER)b == 0) return (number)1;
143  while ((NATNUMBER)a % 2 == 0 && (NATNUMBER)b % 2 == 0)
144  {
145    a = (number)((NATNUMBER)a / 2);
146    b = (number)((NATNUMBER)b / 2);
147    res++;
148  }
149  if ((NATNUMBER)b % 2 == 0)
150  {
151    *t = NULL;
152    *s = nr2mInvers(a,r);
153    return (number)((1L << res)); // * (NATNUMBER) a);  // (2**res)*a    a is a unit
154  }
155  else
156  {
157    *s = NULL;
158    *t = nr2mInvers(b,r);
159    return (number)((1L << res)); // * (NATNUMBER) b);  // (2**res)*b    b is a unit
160  }
161}
162
163void nr2mPower(number a, int i, number * result, const coeffs r)
164{
165  if (i == 0)
166  {
167    *(NATNUMBER *)result = 1;
168  }
169  else if (i == 1)
170  {
171    *result = a;
172  }
173  else
174  {
175    nr2mPower(a, i-1, result, r);
176    *result = nr2mMultM(a, *result, r);
177  }
178}
179
180/*
181 * create a number from int
182 */
183number nr2mInit(int i, const coeffs r)
184{
185  if (i == 0) return (number)(NATNUMBER)i;
186
187  long ii = i;
188  NATNUMBER j = (NATNUMBER)1;
189  if (ii < 0) { j = r->mod2mMask; ii = -ii; }
190  NATNUMBER k = (NATNUMBER)ii;
191  k = k & r->mod2mMask;
192  /* now we have: i = j * k mod 2^m */
193  return (number)nr2mMult((number)j, (number)k, r);
194}
195
196/*
197 * convert a number to an int in ]-k/2 .. k/2],
198 * where k = 2^m; i.e., an int in ]-2^(m-1) .. 2^(m-1)];
199 * note that the code computes a long which will then
200 * automatically casted to int
201 */
202int nr2mInt(number &n, const coeffs r)
203{
204  NATNUMBER nn = (unsigned long)(NATNUMBER)n & r->mod2mMask;
205  unsigned long l = r->mod2mMask >> 1; l++; /* now: l = 2^(m-1) */
206  if ((NATNUMBER)nn > l)
207    return (int)((NATNUMBER)nn - r->mod2mMask - 1);
208  else
209    return (int)((NATNUMBER)nn);
210}
211
212number nr2mAdd(number a, number b, const coeffs r)
213{
214  return nr2mAddM(a, b, r);
215}
216
217number nr2mSub(number a, number b, const coeffs r)
218{
219  return nr2mSubM(a, b, r);
220}
221
222BOOLEAN nr2mIsUnit(number a, const coeffs r)
223{
224  return ((NATNUMBER)a % 2 == 1);
225}
226
227number nr2mGetUnit(number k, const coeffs r)
228{
229  if (k == NULL) return (number)1;
230  NATNUMBER erg = (NATNUMBER)k;
231  while (erg % 2 == 0) erg = erg / 2;
232  return (number)erg;
233}
234
235BOOLEAN nr2mIsZero(number a, const coeffs r)
236{
237  return 0 == (NATNUMBER)a;
238}
239
240BOOLEAN nr2mIsOne(number a, const coeffs r)
241{
242  return 1 == (NATNUMBER)a;
243}
244
245BOOLEAN nr2mIsMOne(number a, const coeffs r)
246{
247  return (r->mod2mMask  == (NATNUMBER)a);
248}
249
250BOOLEAN nr2mEqual(number a, number b, const coeffs r)
251{
252  return (a == b);
253}
254
255BOOLEAN nr2mGreater(number a, number b, const coeffs r)
256{
257  return nr2mDivBy(a, b,r);
258}
259
260/* Is a divisible by b? There are two cases:
261   1) a = 0 mod 2^m; then TRUE iff b = 0 or b is a power of 2
262   2) a, b <> 0; then TRUE iff b/gcd(a, b) is a unit mod 2^m
263   TRUE iff b(gcd(a, b) is a unit */
264BOOLEAN nr2mDivBy (number a, number b, const coeffs r)
265{
266  if (a == NULL)
267  {
268    NATNUMBER c = r->mod2mMask + 1;
269    if (c != 0) /* i.e., if no overflow */
270      return (c % (NATNUMBER)b) == 0;
271    else
272    {
273      /* overflow: we need to check whether b
274         is zero or a power of 2: */
275      c = (NATNUMBER)b;
276      while (c != 0)
277      {
278        if ((c % 2) != 0) return FALSE;
279        c = c >> 1;
280      }
281      return TRUE;
282    }
283  }
284  else
285  {
286    number n = nr2mGcd(a, b, r);
287    n = nr2mDiv(b, n, r);
288    return nr2mIsUnit(n, r);
289  }
290}
291
292int nr2mDivComp(number as, number bs, const coeffs r)
293{
294  NATNUMBER a = (NATNUMBER)as;
295  NATNUMBER b = (NATNUMBER)bs;
296  assume(a != 0 && b != 0);
297  while (a % 2 == 0 && b % 2 == 0)
298  {
299    a = a / 2;
300    b = b / 2;
301  }
302  if (a % 2 == 0)
303  {
304    return -1;
305  }
306  else
307  {
308    if (b % 2 == 1)
309    {
310      return 2;
311    }
312    else
313    {
314      return 1;
315    }
316  }
317}
318
319/* TRUE iff 0 < k <= 2^m / 2 */
320BOOLEAN nr2mGreaterZero(number k, const coeffs r)
321{
322  if ((NATNUMBER)k == 0) return FALSE;
323  if ((NATNUMBER)k > ((r->mod2mMask >> 1) + 1)) return FALSE;
324  return TRUE;
325}
326
327/* assumes that 'a' is odd, i.e., a unit in Z/2^m, and computes
328   the extended gcd of 'a' and 2^m, in order to find some 's'
329   and 't' such that a * s + 2^m * t = gcd(a, 2^m) = 1;
330   this code will always find a positive 's' */
331void specialXGCD(unsigned long& s, unsigned long a, const coeffs r)
332{
333  int_number u = (int_number)omAlloc(sizeof(mpz_t));
334  mpz_init_set_ui(u, a);
335  int_number u0 = (int_number)omAlloc(sizeof(mpz_t));
336  mpz_init(u0);
337  int_number u1 = (int_number)omAlloc(sizeof(mpz_t));
338  mpz_init_set_ui(u1, 1);
339  int_number u2 = (int_number)omAlloc(sizeof(mpz_t));
340  mpz_init(u2);
341  int_number v = (int_number)omAlloc(sizeof(mpz_t));
342  mpz_init_set_ui(v, r->mod2mMask);
343  mpz_add_ui(v, v, 1); /* now: v = 2^m */
344  int_number v0 = (int_number)omAlloc(sizeof(mpz_t));
345  mpz_init(v0);
346  int_number v1 = (int_number)omAlloc(sizeof(mpz_t));
347  mpz_init(v1);
348  int_number v2 = (int_number)omAlloc(sizeof(mpz_t));
349  mpz_init_set_ui(v2, 1);
350  int_number q = (int_number)omAlloc(sizeof(mpz_t));
351  mpz_init(q);
352  int_number rr = (int_number)omAlloc(sizeof(mpz_t));
353  mpz_init(rr);
354
355  while (mpz_cmp_ui(v, 0) != 0) /* i.e., while v != 0 */
356  {
357    mpz_div(q, u, v);
358    mpz_mod(rr, u, v);
359    mpz_set(u, v);
360    mpz_set(v, rr);
361    mpz_set(u0, u2);
362    mpz_set(v0, v2);
363    mpz_mul(u2, u2, q); mpz_sub(u2, u1, u2); /* u2 = u1 - q * u2 */
364    mpz_mul(v2, v2, q); mpz_sub(v2, v1, v2); /* v2 = v1 - q * v2 */
365    mpz_set(u1, u0);
366    mpz_set(v1, v0);
367  }
368
369  while (mpz_cmp_ui(u1, 0) < 0) /* i.e., while u1 < 0 */
370  {
371    /* we add 2^m = (2^m - 1) + 1 to u1: */
372    mpz_add_ui(u1, u1, r->mod2mMask);
373    mpz_add_ui(u1, u1, 1);
374  }
375  s = mpz_get_ui(u1); /* now: 0 <= s <= 2^m - 1 */
376
377  mpz_clear(u);  omFree((ADDRESS)u);
378  mpz_clear(u0); omFree((ADDRESS)u0);
379  mpz_clear(u1); omFree((ADDRESS)u1);
380  mpz_clear(u2); omFree((ADDRESS)u2);
381  mpz_clear(v);  omFree((ADDRESS)v);
382  mpz_clear(v0); omFree((ADDRESS)v0);
383  mpz_clear(v1); omFree((ADDRESS)v1);
384  mpz_clear(v2); omFree((ADDRESS)v2);
385  mpz_clear(q); omFree((ADDRESS)q);
386  mpz_clear(rr); omFree((ADDRESS)rr);
387}
388
389NATNUMBER InvMod(NATNUMBER a, const coeffs r)
390{
391  assume((NATNUMBER)a % 2 != 0);
392  unsigned long s;
393  specialXGCD(s, a, r);
394  return s;
395}
396//#endif
397
398inline number nr2mInversM(number c, const coeffs r)
399{
400  assume((NATNUMBER)c % 2 != 0);
401  // Table !!!
402  NATNUMBER inv;
403  inv = InvMod((NATNUMBER)c,r);
404  return (number)inv;
405}
406
407number nr2mDiv(number a, number b, const coeffs r)
408{
409  if ((NATNUMBER)a == 0) return (number)0;
410  else if ((NATNUMBER)b % 2 == 0)
411  {
412    if ((NATNUMBER)b != 0)
413    {
414      while (((NATNUMBER)b % 2 == 0) && ((NATNUMBER)a % 2 == 0))
415      {
416        a = (number)((NATNUMBER)a / 2);
417        b = (number)((NATNUMBER)b / 2);
418      }
419    }
420    if ((NATNUMBER)b % 2 == 0)
421    {
422      WerrorS("Division not possible, even by cancelling zero divisors.");
423      WerrorS("Result is integer division without remainder.");
424      return (number) ((NATNUMBER) a / (NATNUMBER) b);
425    }
426  }
427  return (number)nr2mMult(a, nr2mInversM(b,r),r);
428}
429
430number nr2mMod(number a, number b, const coeffs r)
431{
432  /*
433    We need to return the number rr which is uniquely determined by the
434    following two properties:
435      (1) 0 <= rr < |b| (with respect to '<' and '<=' performed in Z x Z)
436      (2) There exists some k in the integers Z such that a = k * b + rr.
437    Consider g := gcd(2^m, |b|). Note that then |b|/g is a unit in Z/2^m.
438    Now, there are three cases:
439      (a) g = 1
440          Then |b| is a unit in Z/2^m, i.e. |b| (and also b) divides a.
441          Thus rr = 0.
442      (b) g <> 1 and g divides a
443          Then a = (a/g) * (|b|/g)^(-1) * b (up to sign), i.e. again rr = 0.
444      (c) g <> 1 and g does not divide a
445          Let's denote the division with remainder of a by g as follows:
446          a = s * g + t. Then t = a - s * g = a - s * (|b|/g)^(-1) * |b|
447          fulfills (1) and (2), i.e. rr := t is the correct result. Hence
448          in this third case, rr is the remainder of division of a by g in Z.
449    This algorithm is the same as for the case Z/n, except that we may
450    compute the gcd of |b| and 2^m "by hand": We just extract the highest
451    power of 2 (<= 2^m) that is contained in b.
452  */
453  assume((NATNUMBER)b != 0);
454  NATNUMBER g = 1;
455  NATNUMBER b_div = (NATNUMBER)b;
456  if (b_div < 0) b_div = -b_div; // b_div now represents |b|
457  NATNUMBER rr = 0;
458  while ((g < r->mod2mMask ) && (b_div > 0) && (b_div % 2 == 0))
459  {
460    b_div = b_div >> 1;
461    g = g << 1;
462  } // g is now the gcd of 2^m and |b|
463
464  if (g != 1) rr = (NATNUMBER)a % g;
465  return (number)rr;
466}
467
468number nr2mIntDiv(number a, number b, const coeffs r)
469{
470  if ((NATNUMBER)a == 0)
471  {
472    if ((NATNUMBER)b == 0)
473      return (number)1;
474    if ((NATNUMBER)b == 1)
475      return (number)0;
476    NATNUMBER c = r->mod2mMask + 1;
477    if (c != 0) /* i.e., if no overflow */
478      return (number)(c / (NATNUMBER)b);
479    else
480    {
481      /* overflow: c = 2^32 resp. 2^64, depending on platform */
482      int_number cc = (int_number)omAlloc(sizeof(mpz_t));
483      mpz_init_set_ui(cc, r->mod2mMask); mpz_add_ui(cc, cc, 1);
484      mpz_div_ui(cc, cc, (unsigned long)(NATNUMBER)b);
485      unsigned long s = mpz_get_ui(cc);
486      mpz_clear(cc); omFree((ADDRESS)cc);
487      return (number)(NATNUMBER)s;
488    }
489  }
490  else
491  {
492    if ((NATNUMBER)b == 0)
493      return (number)0;
494    return (number)((NATNUMBER) a / (NATNUMBER) b);
495  }
496}
497
498number nr2mInvers(number c, const coeffs r)
499{
500  if ((NATNUMBER)c % 2 == 0)
501  {
502    WerrorS("division by zero divisor");
503    return (number)0;
504  }
505  return nr2mInversM(c, r);
506}
507
508number nr2mNeg(number c, const coeffs r)
509{
510  if ((NATNUMBER)c == 0) return c;
511  return nr2mNegM(c, r);
512}
513
514number nr2mMapMachineInt(number from, const coeffs src, const coeffs dst)
515{
516  NATNUMBER i = ((NATNUMBER)from) % dst->mod2mMask ;
517  return (number)i;
518}
519
520number nr2mMapZp(number from, const coeffs src, const coeffs dst)
521{
522  NATNUMBER j = (NATNUMBER)1;
523  long ii = (long)from;
524  if (ii < 0) { j = dst->mod2mMask; ii = -ii; }
525  NATNUMBER i = (NATNUMBER)ii;
526  i = i & dst->mod2mMask;
527  /* now we have: from = j * i mod 2^m */
528  return (number)nr2mMult((number)i, (number)j, dst);
529}
530
531number nr2mMapQ(number from, const coeffs src, const coeffs dst)
532{
533  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
534  mpz_init(erg);
535  int_number k = (int_number)omAlloc(sizeof(mpz_t));
536  mpz_init_set_ui(k, dst->mod2mMask);
537
538  nlGMP(from, (number)erg, dst);
539  mpz_and(erg, erg, k);
540  number res = (number)mpz_get_ui(erg);
541
542  mpz_clear(erg); omFree((ADDRESS)erg);
543  mpz_clear(k);   omFree((ADDRESS)k);
544
545  return (number)res;
546}
547
548number nr2mMapGMP(number from, const coeffs src, const coeffs dst)
549{
550  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
551  mpz_init(erg);
552  int_number k = (int_number)omAlloc(sizeof(mpz_t));
553  mpz_init_set_ui(k, dst->mod2mMask);
554
555  mpz_and(erg, (int_number)from, k);
556  number res = (number) mpz_get_ui(erg);
557
558  mpz_clear(erg); omFree((ADDRESS)erg);
559  mpz_clear(k);   omFree((ADDRESS)k);
560
561  return (number)res;
562}
563
564nMapFunc nr2mSetMap(const coeffs src, const coeffs dst)
565{
566  if (nCoeff_is_Ring_2toM(src)
567     && (src->mod2mMask == dst->mod2mMask))
568  {
569    return ndCopyMap;
570  }
571  if (nCoeff_is_Ring_2toM(src)
572     && (src->mod2mMask < dst->mod2mMask))
573  { /* i.e. map an integer mod 2^s into Z mod 2^t, where t < s */
574    return nr2mMapMachineInt;
575  }
576  if (nCoeff_is_Ring_2toM(src)
577     && (src->mod2mMask > dst->mod2mMask))
578  { /* i.e. map an integer mod 2^s into Z mod 2^t, where t > s */
579    // to be done
580  }
581  if (nCoeff_is_Ring_Z(src))
582  {
583    return nr2mMapGMP;
584  }
585  if (nCoeff_is_Q(src))
586  {
587    return nr2mMapQ;
588  }
589  if (nCoeff_is_Zp(src) && (src->ch == 2))
590  {
591    return nr2mMapZp;
592  }
593  if (nCoeff_is_Ring_PtoM(src) || nCoeff_is_Ring_ModN(src))
594  {
595    // Computing the n of Z/n
596    int_number modul = (int_number)omAllocBin(gmp_nrz_bin);
597    mpz_init_set(modul, src->modNumber);
598    int_number twoToTheK = (int_number)omAllocBin(gmp_nrz_bin);
599    mpz_init_set_ui(twoToTheK, src->mod2mMask);
600    mpz_add_ui(twoToTheK, twoToTheK, 1);
601    if (mpz_divisible_p(modul, twoToTheK))
602    {
603      mpz_clear(modul);     omFree((void *)modul);
604      mpz_clear(twoToTheK); omFree((void *)twoToTheK);
605      return nr2mMapGMP;
606    }
607    mpz_clear(modul);     omFree((void *) modul);
608    mpz_clear(twoToTheK); omFree((void *)twoToTheK);
609  }
610  return NULL;      // default
611}
612
613/*
614 * set the exponent
615 */
616
617void nr2mSetExp(int m, coeffs r)
618{
619  if (m > 1)
620  {
621    /* we want mod2mMask to be the bit pattern
622       '111..1' consisting of m one's: */
623    r->mod2mMask = 1;
624    for (int i = 1; i < m; i++) r->mod2mMask = (r->mod2mMask << 1) + 1;
625  }
626  else
627  {
628    /* code unexpectedly called with m = 1; we go on with m = 2: */
629    r->mod2mMask = 3; /* i.e., '11' in binary representation */
630  }
631  r->ch = r->mod2mMask + 1;
632}
633
634void nr2mInitExp(int m, coeffs r)
635{
636  nr2mSetExp(m, r);
637  if (m < 2)
638    WarnS("nr2mInitExp unexpectedly called with m = 1 (we go on with Z/2^2");
639}
640
641#ifdef LDEBUG
642BOOLEAN nr2mDBTest (number a, const char *f, const int l, const coeffs r)
643{
644  if ((NATNUMBER)a < 0) return FALSE;
645  if (((NATNUMBER)a & r->mod2mMask) != (NATNUMBER)a) return FALSE;
646  return TRUE;
647}
648#endif
649
650void nr2mWrite (number &a, const coeffs r)
651{
652  int i = nr2mInt(a, r);
653  StringAppend("%d", i);
654}
655
656static const char* nr2mEati(const char *s, int *i, const coeffs r)
657{
658
659  if (((*s) >= '0') && ((*s) <= '9'))
660  {
661    (*i) = 0;
662    do
663    {
664      (*i) *= 10;
665      (*i) += *s++ - '0';
666      if ((*i) >= (MAX_INT_VAL / 10)) (*i) = (*i) & r->mod2mMask;
667    }
668    while (((*s) >= '0') && ((*s) <= '9'));
669    (*i) = (*i) & r->mod2mMask;
670  }
671  else (*i) = 1;
672  return s;
673}
674
675const char * nr2mRead (const char *s, number *a, const coeffs r)
676{
677  int z;
678  int n=1;
679
680  s = nr2mEati(s, &z,r);
681  if ((*s) == '/')
682  {
683    s++;
684    s = nr2mEati(s, &n,r);
685  }
686  if (n == 1)
687    *a = (number)z;
688  else
689      *a = nr2mDiv((number)z,(number)n,r);
690  return s;
691}
692#endif
693/* #ifdef HAVE_RINGS */
Note: See TracBrowser for help on using the repository browser.