1 //   Copyright (c)  2012-2018  John Abbott and Anna Maria Bigatti
2 
3 //   This file is part of the source of CoCoALib, the CoCoA Library.
4 
5 //   CoCoALib is free software: you can redistribute it and/or modify
6 //   it under the terms of the GNU General Public License as published by
7 //   the Free Software Foundation, either version 3 of the License, or
8 //   (at your option) any later version.
9 
10 //   CoCoALib is distributed in the hope that it will be useful,
11 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //   GNU General Public License for more details.
14 
15 //   You should have received a copy of the GNU General Public License
16 //   along with CoCoALib.  If not, see <http://www.gnu.org/licenses/>.
17 
18 #include "CoCoA/BigIntOps.H"
19 
20 #include "CoCoA/convert.H"
21 #include "CoCoA/error.H"
22 #include "CoCoA/utils.H"
23 
24 #include <cmath>
25 //using std::log;
26 //using std::atan;
27 #include <limits>
28 using std::numeric_limits;
29 
30 
31 
32 namespace CoCoA
33 {
34 
35   namespace //anonymous
36   {
37     // Compute  round(n/d)  rounding halves up.
38     // NB cannot simply do  (n+d/2)/d  because of possible overflow!
uround_half_up(unsigned long n,unsigned long d)39     inline unsigned long uround_half_up(unsigned long n, unsigned long d)
40     {
41       CoCoA_ASSERT(d != 0);
42       const unsigned long q = n/d;
43       if (n-q*d <= (d-1)/2) return q;
44       return q+1; // cannot overflow
45     }
46 
47     // Compute  round(n/d)  rounding halves down.
48     // NB cannot simply do  (n+(d-1)/2)/d  because of possible overflow!
uround_half_down(unsigned long n,unsigned long d)49     inline unsigned long uround_half_down(unsigned long n, unsigned long d)
50     {
51       CoCoA_ASSERT(d != 0);
52       const unsigned long q = n/d;
53       if (n-q*d <= d/2) return q;
54       return q+1; // cannot overflow
55     }
56 
57     // These two defns are used inside cmp(MachineInt, MachineInt)
cmp(long a,long b)58     inline int cmp(long a, long b)
59     {
60       if (a < b) return -1;
61       if (b < a) return 1;
62       return 0;
63     }
64 
cmp(unsigned long a,unsigned long b)65     inline int cmp(unsigned long a, unsigned long b)
66     {
67       if (a < b) return -1;
68       if (b < a) return 1;
69       return 0;
70     }
71 
72   } // end of anonymous namespace
73 
74 
abs(const BigInt & N)75   const BigInt abs(const BigInt& N)
76   {
77     BigInt ans;
78     mpz_abs(mpzref(ans), mpzref(N));
79     return ans;
80   }
81 
82 
83   const BigInt operator-(const BigInt& N)
84   {
85     BigInt ans(N);
86     negate(ans);
87     return ans;
88   }
89 
90 
91   const BigInt operator+(const BigInt& N1, const BigInt& N2)
92   {
93     BigInt ans;
94     mpz_add(mpzref(ans), mpzref(N1), mpzref(N2));
95     return ans;
96   }
97 
98   const BigInt operator+(const BigInt& N1, const MachineInt& n2)
99   {
100     BigInt ans;
101     if (IsNegative(n2))
102       mpz_sub_ui(mpzref(ans), mpzref(N1), negate(n2));
103     else
104       mpz_add_ui(mpzref(ans), mpzref(N1), AsUnsignedLong(n2));
105     return ans;
106   }
107 
108   const BigInt operator+(const MachineInt& n1, const BigInt& N2)
109   {
110     BigInt ans;
111     if (IsNegative(n1))
112       mpz_sub_ui(mpzref(ans), mpzref(N2), negate(n1));
113     else
114       mpz_add_ui(mpzref(ans), mpzref(N2), AsUnsignedLong(n1));
115     return ans;
116   }
117 
118 
119   const BigInt operator-(const BigInt& N1, const BigInt& N2)
120   {
121     BigInt ans;
122     mpz_sub(mpzref(ans), mpzref(N1), mpzref(N2));
123     return ans;
124   }
125 
126   const BigInt operator-(const BigInt& N1, const MachineInt& n2)
127   {
128     BigInt ans;
129     if (IsNegative(n2))
130       mpz_add_ui(mpzref(ans), mpzref(N1), negate(n2));
131     else
132       mpz_sub_ui(mpzref(ans), mpzref(N1), AsUnsignedLong(n2));
133     return ans;
134   }
135 
136   const BigInt operator-(const MachineInt& n1, const BigInt& N2)
137   {
138     BigInt ans;
139     if (IsNegative(n1))
140       mpz_add_ui(mpzref(ans), mpzref(N2), negate(n1));
141     else
142       mpz_sub_ui(mpzref(ans), mpzref(N2), AsUnsignedLong(n1));
143     negate(ans);
144     return ans;
145   }
146 
147 
148   const BigInt operator*(const BigInt& N1, const BigInt& N2)
149   {
150     BigInt ans;
151     mpz_mul(mpzref(ans), mpzref(N1), mpzref(N2));
152     return ans;
153   }
154 
155   const BigInt operator*(const BigInt& N1, const MachineInt& n2)
156   {
157     BigInt ans;
158     if (IsNegative(n2))
159       mpz_mul_si(mpzref(ans), mpzref(N1), AsSignedLong(n2));
160     else
161       mpz_mul_ui(mpzref(ans), mpzref(N1), AsUnsignedLong(n2));
162     return ans;
163   }
164 
165   const BigInt operator*(const MachineInt& n1, const BigInt& N2)
166   {
167     BigInt ans;
168     if (IsNegative(n1))
169       mpz_mul_si(mpzref(ans), mpzref(N2), AsSignedLong(n1));
170     else
171       mpz_mul_ui(mpzref(ans), mpzref(N2), AsUnsignedLong(n1));
172     return ans;
173   }
174 
175 
176   const BigInt operator/(const BigInt& N1, const BigInt& N2)
177   {
178     if (IsZero(N2))
179       CoCoA_THROW_ERROR(ERR::DivByZero, "BigInt / BigInt");
180     BigInt ans;
181     mpz_tdiv_q(mpzref(ans), mpzref(N1), mpzref(N2));
182     return ans;
183   }
184 
185   const BigInt operator/(const BigInt& N1, const MachineInt& n2)
186   {
187     if (IsZero(n2))
188       CoCoA_THROW_ERROR(ERR::DivByZero, "BigInt / MachineInt");
189     BigInt ans;
190     mpz_tdiv_q_ui(mpzref(ans), mpzref(N1), uabs(n2));
191     if (IsNegative(n2))
192       negate(ans);
193 
194     return ans;
195   }
196 
197   // Impl is simple rather than fast.
198   const BigInt operator/(const MachineInt& n1, const BigInt& N2)
199   {
200     if (IsZero(N2))
201       CoCoA_THROW_ERROR(ERR::DivByZero, "MachineInt / BigInt");
202     BigInt ans(n1);
203     ans /= N2;
204     return ans;
205   }
206 
207 
208   const BigInt operator%(const BigInt& N1, const BigInt& N2)
209   {
210     if (IsZero(N2))
211       CoCoA_THROW_ERROR(ERR::ZeroModulus, "BigInt % BigInt");
212     BigInt ans;
213     mpz_tdiv_r(mpzref(ans), mpzref(N1), mpzref(N2));
214     return ans;
215   }
216 
217   // This impl is valid for any second arg, but would then
218   // have to return an unsigned long.  I have decided to forbid
219   // 2nd args which are too big to fit into signed long; this
220   // guarantees that the result will fit into signed long.
221   // An alternative would be simply to NumericCast the result to
222   // long (which will throw if the result doesn't fit).
223   long operator%(const BigInt& N1, const MachineInt& n2)
224   {
225     if (IsZero(n2))
226       CoCoA_THROW_ERROR(ERR::DivByZero, "BigInt % MachineInt");
227     if (!IsSignedLong(n2))
228       CoCoA_THROW_ERROR(ERR::ArgTooBig, "BigInt % MachineInt");
229     const long ans = mpz_tdiv_ui(mpzref(N1), uabs(n2)); // abs value of remainder
230     if (N1 < 0) return -ans; // CAREFUL: read GMP doc for mpz_tdiv_ui
231     return ans;
232   }
233 
234   // Impl is simple rather than fast.
235   const BigInt operator%(const MachineInt& n1, const BigInt& N2)
236   {
237     if (IsZero(N2))
238       CoCoA_THROW_ERROR(ERR::DivByZero, "MachineInt % BigInt");
239     return BigInt(n1)%N2;
240 //    BigInt ans(n1);
241 //    ans %= N2;
242 //    return ans;
243   }
244 
245 
LeastNNegRemainder(const BigInt & N1,const BigInt & N2)246   const BigInt LeastNNegRemainder(const BigInt& N1, const BigInt& N2)
247   {
248     if (IsZero(N2))
249       CoCoA_THROW_ERROR(ERR::ZeroModulus, "LeastNNegRemainder(BigInt, BigInt)");
250     BigInt ans;
251     mpz_mod(mpzref(ans), mpzref(N1), mpzref(N2));
252     return ans;
253   }
254 
LeastNNegRemainder(const BigInt & N1,const MachineInt & n2)255   long LeastNNegRemainder(const BigInt& N1, const MachineInt& n2)
256   {
257     if (IsZero(n2) || !IsSignedLong(n2)) CoCoA_THROW_ERROR(ERR::BadModulus, "LeastNNegRemainder");
258     return mpz_fdiv_ui(mpzref(N1), uabs(n2)); // harmless silent conversion to long
259   }
260 
LeastNNegRemainder(const MachineInt & n1,const BigInt & N2)261   const BigInt LeastNNegRemainder(const MachineInt& n1, const BigInt& N2)
262   {
263     // Simple rather than fast;
264     return LeastNNegRemainder(BigInt(n1), N2);
265   }
266 
LeastNNegRemainder(const MachineInt & n1,const MachineInt & n2)267   long LeastNNegRemainder(const MachineInt& n1, const MachineInt& n2)
268   {
269     if (IsZero(n2) || !IsSignedLong(n2)) CoCoA_THROW_ERROR(ERR::BadModulus, "LeastNNegRemainder");
270     const unsigned long N2 = uabs(n2);
271     const unsigned long ans = uabs(n1)%N2;
272     if (ans != 0 && IsNegative(n1)) return N2-ans; // harmless silent conversion to long
273     return ans; // harmless silent conversion to long
274   }
275 
276 
SymmRemainder(const BigInt & N1,const BigInt & N2)277   const BigInt SymmRemainder(const BigInt& N1, const BigInt& N2)
278   {
279     if (IsZero(N2))
280       CoCoA_THROW_ERROR(ERR::ZeroModulus, "SymmRemainder(BigInt, BigInt)");
281     BigInt ans;
282     mpz_tdiv_r(mpzref(ans), mpzref(N1), mpzref(N2));
283     BigInt HalfN2; mpz_tdiv_q_2exp(mpzref(HalfN2), mpzref(N2), 1); mpz_abs(mpzref(HalfN2), mpzref(HalfN2));
284     if (CmpAbs(ans, HalfN2) < 0) return ans;
285     if (ans == HalfN2) return ans;
286     if (sign(ans) == sign(N2)) ans -= N2;
287     else ans += N2;
288     return ans;
289   }
290 
SymmRemainder(const BigInt & N1,const MachineInt & n2)291   long SymmRemainder(const BigInt& N1, const MachineInt& n2)
292   {
293     if (IsZero(n2) || !IsSignedLong(n2)) CoCoA_THROW_ERROR(ERR::BadModulus, "SymmRemainder");
294     const unsigned long N2 = uabs(n2);
295     unsigned long ans = mpz_fdiv_ui(mpzref(N1), N2);
296     if (ans > N2/2) return -NumericCast<long>(N2-ans); // cannot overflow (on a binary computer)
297     return ans;
298   }
299 
SymmRemainder(const MachineInt & n1,const BigInt & N2)300   const BigInt SymmRemainder(const MachineInt& n1, const BigInt& N2)
301   {
302     // Simple rather than fast.
303     return SymmRemainder(BigInt(n1), N2);
304   }
305 
306 
SymmRemainder(const MachineInt & n1,const MachineInt & n2)307   long SymmRemainder(const MachineInt& n1, const MachineInt& n2)
308   {
309     if (IsZero(n2) || !IsSignedLong(n2)) CoCoA_THROW_ERROR(ERR::BadModulus, "SymmRemainder");
310     const unsigned long N2 = uabs(n2);
311     unsigned long ans = uabs(n1)%N2;
312     if (IsNegative(n1)) ans = N2-ans;
313     if (ans > N2/2) return -NumericCast<long>(N2-ans); // cannot overflow (on a binary computer)
314     return ans;
315   }
316 
317 
power(const BigInt & base,const BigInt & exponent)318   const BigInt power(const BigInt& base, const BigInt& exponent)
319   {
320     if (exponent < 0)
321       CoCoA_THROW_ERROR(ERR::NegExp, "power(BigInt, BigInt)");
322     // BUG??? Below could allow high powers of 0 and +/-1.  Is it worth it?
323     unsigned long exp;
324     if (!IsConvertible(exp, exponent))
325       CoCoA_THROW_ERROR(ERR::ExpTooBig, "power(BigInt, BigInt)");
326     BigInt ans;
327     mpz_pow_ui(mpzref(ans), mpzref(base), exp);
328     return ans;
329   }
330 
power(const BigInt & base,const MachineInt & exponent)331   const BigInt power(const BigInt& base, const MachineInt& exponent)
332   {
333     if (IsNegative(exponent))
334       CoCoA_THROW_ERROR(ERR::NegExp, "power(BigInt, MachineInt)");
335     BigInt ans;
336     mpz_pow_ui(mpzref(ans), mpzref(base), AsUnsignedLong(exponent));
337     return ans;
338   }
339 
power(const MachineInt & base,const BigInt & exponent)340   const BigInt power(const MachineInt& base, const BigInt& exponent)
341   {
342     const char* const FnName = "power(MachineInt, BigInt)";
343     if (exponent < 0)
344       CoCoA_THROW_ERROR(ERR::NegExp, FnName);
345     // BUG???  Below could allow high powers of 0 and +/-1.  Is it worth it?
346     unsigned long exp;
347     if (!IsConvertible(exp, exponent))
348       CoCoA_THROW_ERROR(ERR::ExpTooBig, FnName);
349     const bool NegateResult = IsNegative(base) & IsOdd(exp);
350     const unsigned long B = uabs(base);
351     BigInt ans;
352     mpz_ui_pow_ui(mpzref(ans), B, exp);
353     if (NegateResult)
354       negate(ans);
355     return ans;
356   }
357 
power(const MachineInt & base,const MachineInt & exponent)358   const BigInt power(const MachineInt& base, const MachineInt& exponent)
359   {
360     const char* const FnName = "power(MachineInt, MachineInt)";
361     if (IsNegative(exponent))
362       CoCoA_THROW_ERROR(ERR::NegExp, FnName);
363 
364     const bool NegateResult = IsNegative(base) & IsOdd(AsUnsignedLong(exponent));
365     const unsigned long B = uabs(base);
366     BigInt ans;
367     mpz_ui_pow_ui(mpzref(ans), B, AsUnsignedLong(exponent));
368     if (NegateResult)
369       negate(ans);
370     return ans;
371   }
372 
373 
SmallPower(const MachineInt & base,const MachineInt & exponent)374   long SmallPower(const MachineInt& base, const MachineInt& exponent)
375   {
376     if (IsNegative(exponent)) CoCoA_THROW_ERROR(ERR::NegExp, "SmallPower");
377     if (!IsSignedLong(base)) CoCoA_THROW_ERROR(ERR::BadArg, "SmallPower: base is too big to fit into a long");
378     if (IsZero(exponent)) return 1; // Order is important for  0^0
379     if (IsZero(base)) return 0;     // ...
380     long b = AsSignedLong(base);
381     if (b == 1) return 1;
382     unsigned long e = AsUnsignedLong(exponent);
383     if (b == -1) return (IsEven(e)?1:-1);
384     const bool negative = (e&1) && IsNegative(base);
385     long ans = 1;
386     while (e != 1)
387     {
388       if (e&1) ans *= b;
389       e >>= 1;
390       b *= b;
391     }
392     ans *= b;
393     if (negative) return -ans;
394     return ans;
395   }
396 
397 
add(BigInt & lhs,const BigInt & N1,const BigInt & N2)398   void add(BigInt& lhs, const BigInt& N1, const BigInt& N2)
399   {
400     mpz_add(mpzref(lhs), mpzref(N1), mpzref(N2));
401   }
402 
add(BigInt & lhs,const BigInt & N1,const MachineInt & n2)403   void add(BigInt& lhs, const BigInt& N1, const MachineInt& n2)
404   {
405     if (IsNegative(n2))
406       mpz_sub_ui(mpzref(lhs), mpzref(N1), negate(n2));
407     else
408       mpz_add_ui(mpzref(lhs), mpzref(N1), AsUnsignedLong(n2));
409   }
410 
add(BigInt & lhs,const MachineInt & n1,const BigInt & N2)411   void add(BigInt& lhs, const MachineInt& n1, const BigInt& N2)
412   {
413     add(lhs, N2, n1);
414   }
415 
416 
sub(BigInt & lhs,const BigInt & N1,const BigInt & N2)417   void sub(BigInt& lhs, const BigInt& N1, const BigInt& N2)
418   {
419     mpz_sub(mpzref(lhs), mpzref(N1), mpzref(N2));
420   }
421 
sub(BigInt & lhs,const BigInt & N1,const MachineInt & n2)422   void sub(BigInt& lhs, const BigInt& N1, const MachineInt& n2)
423   {
424     if (IsNegative(n2))
425       mpz_add_ui(mpzref(lhs), mpzref(N1), negate(n2));
426     else
427       mpz_sub_ui(mpzref(lhs), mpzref(N1), AsUnsignedLong(n2));
428   }
429 
sub(BigInt & lhs,const MachineInt & n1,const BigInt & N2)430   void sub(BigInt& lhs, const MachineInt& n1, const BigInt& N2)
431   {
432     sub(lhs, N2, n1);
433     negate(lhs);
434   }
435 
436 
mul(BigInt & lhs,const BigInt & N1,const BigInt & N2)437   void mul(BigInt& lhs, const BigInt& N1, const BigInt& N2)
438   {
439     mpz_mul(mpzref(lhs), mpzref(N1), mpzref(N2));
440   }
441 
mul(BigInt & lhs,const BigInt & N1,const MachineInt & n2)442   void mul(BigInt& lhs, const BigInt& N1, const MachineInt& n2)
443   {
444     if (IsNegative(n2))
445       mpz_mul_si(mpzref(lhs), mpzref(N1), AsSignedLong(n2));
446     else
447       mpz_mul_ui(mpzref(lhs), mpzref(N1), AsUnsignedLong(n2));
448   }
449 
mul(BigInt & lhs,const MachineInt & n1,const BigInt & N2)450   void mul(BigInt& lhs, const MachineInt& n1, const BigInt& N2)
451   {
452     mul(lhs, N2, n1);
453   }
454 
455 
div(BigInt & lhs,const BigInt & N1,const BigInt & N2)456   void div(BigInt& lhs, const BigInt& N1, const BigInt& N2)
457   {
458     if (IsZero(N2))
459       CoCoA_THROW_ERROR(ERR::DivByZero, "div(BigInt, BigInt, BigInt)");
460     mpz_tdiv_q(mpzref(lhs), mpzref(N1), mpzref(N2));
461   }
462 
div(BigInt & lhs,const BigInt & N1,const MachineInt & n2)463   void div(BigInt& lhs, const BigInt& N1, const MachineInt& n2)
464   {
465     if (IsZero(n2))
466       CoCoA_THROW_ERROR(ERR::DivByZero, "div(BigInt, BigInt, MachineInt)");
467     mpz_tdiv_q_ui(mpzref(lhs), mpzref(N1), uabs(n2));
468     if (IsNegative(n2))
469       negate(lhs);
470   }
471 
472   // Impl is simple rather than fast.
div(BigInt & lhs,const MachineInt & n1,const BigInt & N2)473   void div(BigInt& lhs, const MachineInt& n1, const BigInt& N2)
474   {
475     if (N2 == 0)
476       CoCoA_THROW_ERROR(ERR::DivByZero, "div(BigInt, MachineInt, BigInt)");
477     div(lhs, BigInt(n1), N2);
478   }
479 
480 
mod(BigInt & lhs,const BigInt & N1,const BigInt & N2)481   void mod(BigInt& lhs, const BigInt& N1, const BigInt& N2)
482   {
483     if (IsZero(N2))
484       CoCoA_THROW_ERROR(ERR::ZeroModulus, "mod(BigInt, BigInt, BigInt)");
485     mpz_tdiv_r(mpzref(lhs), mpzref(N1), mpzref(N2));
486   }
487 
mod(BigInt & lhs,const BigInt & N1,const MachineInt & n2)488   void mod(BigInt& lhs, const BigInt& N1, const MachineInt& n2)
489   {
490     if (IsZero(n2))
491       CoCoA_THROW_ERROR(ERR::ZeroModulus, "mod(BigInt, BigInt, MachineInt)");
492     mpz_tdiv_r_ui(mpzref(lhs), mpzref(N1), uabs(n2));
493   }
494 
495   // Impl is simple rather than fast.
mod(BigInt & lhs,const MachineInt & n1,const BigInt & N2)496   void mod(BigInt& lhs, const MachineInt& n1, const BigInt& N2)
497   {
498     if (IsZero(N2))
499       CoCoA_THROW_ERROR(ERR::ZeroModulus, "mod(BigInt, MachineInt, BigInt)");
500     mod(lhs, BigInt(n1), N2);
501   }
502 
503 
quorem(BigInt & quo,BigInt & rem,const BigInt & num,const BigInt & den)504   void quorem(BigInt& quo, BigInt& rem, const BigInt& num, const BigInt& den)
505   {
506     if (IsZero(den))
507       CoCoA_THROW_ERROR(ERR::DivByZero, "quorem(BigInt, BigInt, BigInt, BigInt)");
508     mpz_tdiv_qr(mpzref(quo), mpzref(rem), mpzref(num), mpzref(den));
509   }
510 
quorem(BigInt & quo,BigInt & rem,const BigInt & num,const MachineInt & den)511   void quorem(BigInt& quo, BigInt& rem, const BigInt& num, const MachineInt& den)
512   {
513     if (IsZero(den))
514       CoCoA_THROW_ERROR(ERR::DivByZero, "quorem(BigInt, BigInt, BigInt, MachineInt)");
515     if (IsNegative(den))
516     {
517       mpz_tdiv_qr_ui(mpzref(quo), mpzref(rem), mpzref(num), negate(den));
518       negate(quo);
519     }
520     else
521       mpz_tdiv_qr_ui(mpzref(quo), mpzref(rem), mpzref(num), AsUnsignedLong(den));
522   }
523 
524   // Impl is simple rather than fast.
quorem(BigInt & quo,BigInt & rem,const MachineInt & num,const BigInt & den)525   void quorem(BigInt& quo, BigInt& rem, const MachineInt& num, const BigInt& den)
526   {
527     if (IsZero(den))
528       CoCoA_THROW_ERROR(ERR::DivByZero, "quorem(BigInt, BigInt, MachineInt, BigInt)");
529     quorem(quo, rem, BigInt(num), den);
530   }
531 
532 
divexact(BigInt & lhs,const BigInt & N1,const BigInt & N2)533   void divexact(BigInt& lhs, const BigInt& N1, const BigInt& N2)
534   {
535     CoCoA_ASSERT(N1%N2 == 0);
536     mpz_divexact(mpzref(lhs), mpzref(N1), mpzref(N2));
537   }
538 
539 //???  void divexact(BigInt& lhs, const MachineInt& N1, const BigInt& N2);
540 //???  void divexact(BigInt& lhs, const BigInt& N1, const MachineInt& N2);
541 
542 
IsZero(const BigInt & N)543   bool IsZero(const BigInt& N)
544   {
545     return mpz_sgn(mpzref(N))==0;
546   }
547 
IsOne(const BigInt & N)548   bool IsOne(const BigInt& N)
549   {
550     return mpz_cmp_ui(mpzref(N), 1)==0;
551   }
552 
IsMinusOne(const BigInt & N)553   bool IsMinusOne(const BigInt& N)
554   {
555     return mpz_cmp_si(mpzref(N),-1)==0;
556   }
557 
558 
IsPowerOf2(const BigInt & N)559   bool IsPowerOf2(const BigInt& N)
560   {
561     if (N <= 0) return false;
562     const unsigned long LogN = mpz_sizeinbase(mpzref(N), 2)-1;
563     const unsigned long Last1Bit = mpz_scan1(mpzref(N), 0);
564     return (Last1Bit == LogN);
565   }
566 
IsPowerOf2(const MachineInt & n)567   bool IsPowerOf2(const MachineInt& n)
568   {
569     if (IsZero(n) || IsNegative(n)) return false;
570     const unsigned long N = AsUnsignedLong(n);
571     return !(N & (N-1));
572   }
573 
574 
IsDivisible(const MachineInt & N,const MachineInt & D)575   bool IsDivisible(const MachineInt& N, const MachineInt& D) // is N divisibile by D?
576   {
577     if (IsZero(D)) CoCoA_THROW_ERROR(ERR::DivByZero, "IsDivisible");
578     return uabs(N)%uabs(D) == 0;
579   }
580 
IsDivisible(const MachineInt & N,const BigInt & D)581   bool IsDivisible(const MachineInt& N, const BigInt& D) // is N divisibile by D?
582   {
583     if (IsZero(D)) CoCoA_THROW_ERROR(ERR::DivByZero, "IsDivisible");
584     // Simple rather than fast...
585     return IsDivisible(BigInt(N), D);
586   }
587 
IsDivisible(const BigInt & N,const MachineInt & D)588   bool IsDivisible(const BigInt& N, const MachineInt& D) // is N divisibile by D?
589   {
590     if (IsZero(D)) CoCoA_THROW_ERROR(ERR::DivByZero, "IsDivisible");
591     return mpz_divisible_ui_p(mpzref(N), uabs(D));
592   }
593 
IsDivisible(const BigInt & N,const BigInt & D)594   bool IsDivisible(const BigInt& N, const BigInt& D) // is N divisibile by D?
595   {
596     if (IsZero(D)) CoCoA_THROW_ERROR(ERR::DivByZero, "IsDivisible");
597     return mpz_divisible_p(mpzref(N), mpzref(D));
598   }
599 
600 
cmp(const BigInt & N1,const BigInt & N2)601   int cmp(const BigInt& N1, const BigInt& N2)
602   {
603     return sign(mpz_cmp(mpzref(N1), mpzref(N2)));
604   }
605 
cmp(const BigInt & N1,const MachineInt & n2)606   int cmp(const BigInt& N1, const MachineInt& n2)
607   {
608     if (IsNegative(n2))
609       return sign(mpz_cmp_si(mpzref(N1), AsSignedLong(n2)));
610     else
611       return sign(mpz_cmp_ui(mpzref(N1), AsUnsignedLong(n2)));
612   }
613 
cmp(const MachineInt & n1,const BigInt & N2)614   int cmp(const MachineInt& n1, const BigInt& N2)
615   {
616     return -cmp(N2, n1);
617   }
618 
cmp(const MachineInt & n1,const MachineInt & n2)619   int cmp(const MachineInt& n1, const MachineInt& n2)
620   {
621     if (IsNegative(n1))
622     {
623       if (IsNegative(n2))
624         return cmp(AsSignedLong(n1), AsSignedLong(n2));
625       else
626         return -1;
627     }
628     // n1 is non-negative
629     if (IsNegative(n2)) return 1;
630     // Both n1 and n2 are non-negative
631     return cmp(AsUnsignedLong(n1), AsUnsignedLong(n2));
632   }
633 
634 
CmpAbs(const BigInt & N1,const BigInt & N2)635   int CmpAbs(const BigInt& N1, const BigInt& N2)
636   {
637     return sign(mpz_cmpabs(mpzref(N1), mpzref(N2)));
638   }
639 
CmpAbs(const BigInt & N1,const MachineInt & n2)640   int CmpAbs(const BigInt& N1, const MachineInt& n2)
641   {
642     return sign(mpz_cmpabs_ui(mpzref(N1), uabs(n2)));
643   }
644 
CmpAbs(const MachineInt & n1,const BigInt & N2)645   int CmpAbs(const MachineInt& n1, const BigInt& N2)
646   {
647     return -sign(mpz_cmpabs_ui(mpzref(N2), uabs(n1)));
648   }
649 
CmpAbs(const MachineInt & n1,const MachineInt & n2)650   int CmpAbs(const MachineInt& n1, const MachineInt& n2)
651   {
652     const unsigned long a1 = uabs(n1);
653     const unsigned long a2 = uabs(n2);
654     if (a1 > a2) return 1;
655     if (a1 < a2) return -1;
656     return 0;
657   }
658 
659 
660 
661   bool operator==(const BigInt& N1, const BigInt& N2)
662   {
663     return cmp(N1, N2) == 0;
664   }
665 
666   bool operator==(const BigInt& N1, const MachineInt& n2)
667   {
668     return cmp(N1, n2) == 0;
669   }
670 
671   bool operator==(const MachineInt& n1, const BigInt& N2)
672   {
673     return cmp(n1, N2) == 0;
674   }
675 
676 
677   bool operator!=(const BigInt& N1, const BigInt& N2)
678   {
679     return cmp(N1, N2) != 0;
680   }
681 
682   bool operator!=(const BigInt& N1, const MachineInt& n2)
683   {
684     return cmp(N1, n2) != 0;
685   }
686 
687   bool operator!=(const MachineInt& n1, const BigInt& N2)
688   {
689     return cmp(n1, N2) != 0;
690   }
691 
692 
693   bool operator> (const BigInt& N1, const BigInt& N2)
694   {
695     return cmp(N1, N2) > 0;
696   }
697 
698   bool operator> (const BigInt& N1, const MachineInt& n2)
699   {
700     return cmp(N1, n2) > 0;
701   }
702 
703   bool operator> (const MachineInt& n1, const BigInt& N2)
704   {
705     return cmp(n1, N2) > 0;
706   }
707 
708 
709   bool operator>=(const BigInt& N1, const BigInt& N2)
710   {
711     return cmp(N1, N2) >= 0;
712   }
713 
714   bool operator>=(const BigInt& N1, const MachineInt& n2)
715   {
716     return cmp(N1, n2) >= 0;
717   }
718 
719   bool operator>=(const MachineInt& n1, const BigInt& N2)
720   {
721     return cmp(n1, N2) >= 0;
722   }
723 
724 
725   bool operator< (const BigInt& N1, const BigInt& N2)
726   {
727     return cmp(N1, N2) < 0;
728   }
729 
730   bool operator< (const BigInt& N1, const MachineInt& n2)
731   {
732     return cmp(N1, n2) < 0;
733   }
734 
735   bool operator< (const MachineInt& n1, const BigInt& N2)
736   {
737     return cmp(n1, N2) < 0;
738   }
739 
740 
741   bool operator<=(const BigInt& N1, const BigInt& N2)
742   {
743     return cmp(N1, N2) <= 0;
744   }
745 
746   bool operator<=(const BigInt& N1, const MachineInt& n2)
747   {
748     return cmp(N1, n2) <= 0;
749   }
750 
751   bool operator<=(const MachineInt& n1, const BigInt& N2)
752   {
753     return cmp(n1, N2) <= 0;
754   }
755 
756 
mantissa(const BigInt & N)757   double mantissa(const BigInt& N)
758   {
759     long DiscardExponent;
760     return mpz_get_d_2exp(&DiscardExponent, mpzref(N));
761   }
762 
763 
exponent(const BigInt & N)764   long exponent(const BigInt& N)
765   {
766     return NumericCast<long>(mpz_sizeinbase(mpzref(N), 2));
767   }
768 
769 
MultiplicityOf2(const BigInt & N)770   long MultiplicityOf2(const BigInt& N)
771   {
772     if (IsZero(N)) CoCoA_THROW_ERROR(ERR::NotNonZero, "MultiplicityOf2");
773     return mpz_scan1(mpzref(N), 0);
774   }
775 
MultiplicityOf2(const MachineInt & n)776   long MultiplicityOf2(const MachineInt& n)
777   {
778     if (IsZero(n)) CoCoA_THROW_ERROR(ERR::NotNonZero, "MultiplicityOf2");
779     long val = AsSignedLong(n);
780     int i=0;
781     while ((val&1) == 0) { val /= 2; ++i; }
782     return i;
783   }
784 
785 
SizeInBase(const BigInt & N,long base)786   long SizeInBase(const BigInt& N, long base)
787   {
788     if (base < 2 || base > 36)
789       CoCoA_THROW_ERROR(ERR::BadNumBase, "SizeInBase(BigInt,base)");
790     return NumericCast<long>(mpz_sizeinbase(mpzref(N), base));
791   }
792 
793 
log(const BigInt & N)794   double log(const BigInt& N)
795   {
796     if (IsZero(N))
797       CoCoA_THROW_ERROR(ERR::LogZero, "log(BigInt)");
798     if (exponent(N) < numeric_limits<double>::max_exponent)
799       return std::log(std::abs(ConvertTo<double>(N)));
800     long exp;
801     const double mantissa = mpz_get_d_2exp(&exp, mpzref(N));
802     const static double log2 = std::log(2.0);
803     return std::log(std::abs(mantissa)) + exp*log2;
804   }
805 
806 
FloorLog2(const MachineInt & n)807   long FloorLog2(const MachineInt& n) { return FloorLogBase(n,2); }
FloorLog2(const BigInt & N)808   long FloorLog2(const BigInt& N) { return FloorLogBase(N,2); }
FloorLog10(const MachineInt & n)809   long FloorLog10(const MachineInt& n) { return FloorLogBase(n,10); }
FloorLog10(const BigInt & N)810   long FloorLog10(const BigInt& N) { return FloorLogBase(N,10); }
811 
812 
FloorLogBase(const MachineInt & n,const MachineInt & base)813   long FloorLogBase(const MachineInt& n, const MachineInt& base)
814   {
815     return FloorLogBase(BigInt(n), BigInt(base));
816   }
817 
FloorLogBase(const MachineInt & n,const BigInt & base)818   long FloorLogBase(const MachineInt& n, const BigInt& base)
819   {
820     return FloorLogBase(BigInt(n), base);
821   }
822 
FloorLogBase(const BigInt & N,const MachineInt & base)823   long FloorLogBase(const BigInt& N, const MachineInt& base)
824   {
825     return FloorLogBase(N, BigInt(base));
826   }
827 
FloorLogBase(const BigInt & N,const BigInt & base)828   long FloorLogBase(const BigInt& N, const BigInt& base)
829   {
830     if (abs(base) < 2) CoCoA_THROW_ERROR(ERR::BadArg, "FloorLogBase: base must be at least 2");
831     if (IsZero(N)) CoCoA_THROW_ERROR(ERR::LogZero, "FloorLogBase");
832     const double ApproxLog = log(N)/log(base);
833     // Check whether ApproxLog is far from integer.
834     const double delta = 5* ApproxLog * numeric_limits<double>::epsilon();
835     const long candidate = static_cast<long>(floor(ApproxLog+delta)); // probably right but could be too big by 1
836     if (std::abs(ApproxLog - candidate) > delta)
837       return candidate;
838     // ApproxLog was close to integer, so we make a slow but sure check.
839     const BigInt pwr = power(base, candidate);
840     const int test = cmp(abs(N), pwr);
841     if (test == 0) return candidate;
842     if (test < 0) return candidate-1;
843     if (abs(N) >= base*pwr) return candidate+1;
844     return candidate;
845   }
846 
847 
848   // This fn comes out a long horrible mess because I cannot return a
849   // machine int as a BigInt.  There must be a design error somewhere.
RangeFactorial(const MachineInt & lo,const MachineInt & hi)850   BigInt RangeFactorial(const MachineInt& lo, const MachineInt& hi)
851   {
852     BigInt ans;
853     // If zero is in the range, result is zero
854     if ((IsZero(lo) || IsNegative(lo)) && !IsNegative(hi)) return ans;
855     ans = 1;
856     // First some checks for empty products.
857     if (IsNegative(hi) && !IsNegative(lo)) return ans;
858     // We now know that hi and lo have the same sign.
859     // Two more checks for empty products.
860     if (IsNegative(lo) && AsSignedLong(lo) > AsSignedLong(hi)) return ans;
861     if (!IsNegative(lo) && AsUnsignedLong(lo) > AsUnsignedLong(hi)) return ans;
862     // We now know that the product is not empty & does not span 0.
863     unsigned long l = uabs(lo);
864     unsigned long h = uabs(hi);
865     if (IsNegative(hi))
866     {
867       std::swap(l, h);
868       if (((h^l)&1) == 0) negate(ans);
869     }
870 
871     if (h-l > 15)
872     {
873       const unsigned long mid = l + (h-l)/2; // equiv to (l+h)/2 but avoids overflow
874       return RangeFactorial(l,mid) * RangeFactorial(1+mid,h);
875     }
876     // From here on 0 < l < h.
877     for (; l <= h; ++l)
878     {
879       ans *= l;
880 //      mpz_mul_ui(mpzref(ans), mpzref(ans), l);
881     }
882     return ans;
883   }
884 
factorial(const BigInt & N)885   const BigInt factorial(const BigInt& N)
886   {
887     if (N < 0)
888       CoCoA_THROW_ERROR(ERR::NotNonNegative, "factorial(BigInt)");
889     unsigned long n;
890     if (!IsConvertible(n, N))
891       CoCoA_THROW_ERROR(ERR::ArgTooBig, "factorial(BigInt)");
892 //    return factorial(n);
893     BigInt ans;
894     mpz_fac_ui(mpzref(ans), n);
895     return ans;
896   }
897 
898 
factorial(const MachineInt & n)899   const BigInt factorial(const MachineInt& n)
900   {
901     if (IsNegative(n))
902       CoCoA_THROW_ERROR(ERR::NotNonNegative, "factorial(MachineInt)");
903     BigInt ans;
904     mpz_fac_ui(mpzref(ans), AsUnsignedLong(n));
905     return ans;
906   }
907 
908 
909 // From Wikipedia; apparently due to Ramanujan
910 // Experimentally max error is 4.6*10^(-8) at n=24.
LogFactorial(const MachineInt & N)911 double LogFactorial(const MachineInt& N)
912 {
913   using std::log;
914   using std::atan;
915   if (IsNegative(N)) CoCoA_THROW_ERROR(ERR::NotNonNegative, "LogFactorial");
916   const long n = AsSignedLong(N);
917   const static double LogSqrtPi = log(4*atan(1.0))/2;
918   if (n > 23)
919     return n*log(double(n))-n + log(n*(1+n*(4.0+8*n)))/6 + LogSqrtPi;
920   double fact = 1.0;
921   for (long k=2; k <= n; ++k)
922     fact *= k;
923   return log(fact);
924 }
925 
LogFactorial(const BigInt & N)926 double LogFactorial(const BigInt& N)
927 {
928   if (N < 0) CoCoA_THROW_ERROR(ERR::NotNonNegative, "LogFactorial");
929   double n;
930   if (!IsConvertible(n, N)) CoCoA_THROW_ERROR(ERR::ArgTooBig, "LogFactorial");
931   {
932     long SmallN;
933     if (IsConvertible(SmallN, N)) return LogFactorial(SmallN);
934   }
935   using std::log;
936   using std::atan;
937   const static double LogSqrtPi = log(4*atan(1.0))/2;
938   return n*log(n)-n + log(n*(1+n*(4.0+8*n)))/6 + LogSqrtPi;
939 }
940 
941 
942 
primorial(const BigInt & N)943   const BigInt primorial(const BigInt& N)
944   {
945     if (N < 0)
946       CoCoA_THROW_ERROR(ERR::NotNonNegative, "primorial(BigInt)");
947     unsigned long n;
948     if (!IsConvertible(n, N))
949       CoCoA_THROW_ERROR(ERR::ArgTooBig, "primorial(BigInt)");
950 //    return factorial(n);
951     BigInt ans;
952     mpz_primorial_ui(mpzref(ans), n);
953     return ans;
954   }
955 
956 
primorial(const MachineInt & n)957   const BigInt primorial(const MachineInt& n)
958   {
959     if (IsNegative(n))
960       CoCoA_THROW_ERROR(ERR::NotNonNegative, "factorial(MachineInt)");
961     BigInt ans;
962     mpz_primorial_ui(mpzref(ans), AsUnsignedLong(n));
963     return ans;
964   }
965 
966 
binomial(const BigInt & N,const BigInt & R)967   const BigInt binomial(const BigInt& N, const BigInt& R)
968   {
969 //    if (R < 0) return BigInt(0);
970     if (R < 0)
971       CoCoA_THROW_ERROR(ERR::BadArg, "binomial(BigInt,BigInt): 2nd arg must be non-neg");
972     if (N < 0)
973     {
974       if (IsEven(R)) return binomial(R-N-1,R);
975       else return -binomial(R-N-1,R);
976     }
977     if (R > N)
978       return BigInt(0);
979 
980     // General case:  N >= R >= 0
981     unsigned long r;
982     const bool RIsSmall = (2*R < N);
983     if ((RIsSmall && !IsConvertible(r, R)) ||
984         (!RIsSmall && !IsConvertible(r, N-R)))
985       CoCoA_THROW_ERROR(ERR::ArgTooBig, "binomial(BigInt, BigInt)");
986 
987     BigInt ans;
988     mpz_bin_ui(mpzref(ans), mpzref(N), r); // we know that r >= 0.
989     return ans;
990   }
991 
992 
binomial(const MachineInt & n,const BigInt & R)993   const BigInt binomial(const MachineInt& n, const BigInt& R)
994   {
995     if (R < 0)
996       CoCoA_THROW_ERROR(ERR::BadArg, "binomial(MachineInt,BigInt): 2nd arg must be non-neg");
997     return binomial(BigInt(n), R);
998   }
999 
1000 
binomial(const BigInt & N,const MachineInt & r)1001   const BigInt binomial(const BigInt& N, const MachineInt& r)
1002   {
1003 //    if (IsNegative(r)) return BigInt(0);
1004     if (IsNegative(r))
1005       CoCoA_THROW_ERROR(ERR::BadArg, "binomial(BigInt,MachineInt): 2nd arg must be non-neg");
1006     BigInt ans;
1007     mpz_bin_ui(mpzref(ans), mpzref(N), AsUnsignedLong(r));
1008     return ans;
1009   }
1010 
1011 
binomial(const MachineInt & n,const MachineInt & r)1012   const BigInt binomial(const MachineInt& n, const MachineInt& r)
1013   {
1014 //    if (IsNegative(r)) return BigInt(0);
1015     if (IsNegative(r))
1016       CoCoA_THROW_ERROR(ERR::BadArg, "binomial(MachineInt,MachineInt): 2nd arg must be non-neg");
1017 
1018     BigInt ans;
1019     if (IsNegative(n))
1020       mpz_bin_ui(mpzref(ans), mpzref(BigInt(n)), AsUnsignedLong(r));
1021     else
1022       mpz_bin_uiui(mpzref(ans), AsUnsignedLong(n), AsUnsignedLong(r));
1023     return ans;
1024   }
1025 
1026 
fibonacci(const BigInt & N)1027   const BigInt fibonacci(const BigInt& N)
1028   {
1029     long n;
1030     if (!IsConvertible(n, N))
1031       CoCoA_THROW_ERROR(ERR::ArgTooBig, "fibonacci(BigInt)");
1032     return fibonacci(n);
1033   }
1034 
1035 
fibonacci(const MachineInt & n)1036   const BigInt fibonacci(const MachineInt& n)
1037   {
1038     const bool EvenNegative = IsNegative(n) && IsEven(n);
1039     BigInt ans;
1040     unsigned long arg = uabs(n);
1041     mpz_fib_ui(mpzref(ans), arg);
1042     if (EvenNegative)
1043       negate(ans);
1044     return ans;
1045   }
1046 
1047 
1048   // NB halves are rounded away from zero.
RoundDiv(const BigInt & num,const BigInt & den)1049   const BigInt RoundDiv(const BigInt& num, const BigInt& den)
1050   {
1051     if (IsZero(den))
1052       CoCoA_THROW_ERROR(ERR::DivByZero, "RoundDiv(BigInt,BigInt)");
1053     BigInt q,r;
1054     quorem(q, r, num, den);
1055     if (CmpAbs(2*r,den) >= 0) // ROUND AWAY FROM ZERO
1056 //    if (CmpAbs(2*r,den) > 0) // ROUND TOWARDS ZERO
1057       q += sign(r)*sign(den);
1058     return q;
1059   }
1060 
RoundDiv(const BigInt & num,const MachineInt & den)1061   const BigInt RoundDiv(const BigInt& num, const MachineInt& den)
1062   {
1063     if (IsZero(den))
1064       CoCoA_THROW_ERROR(ERR::DivByZero, "RoundDiv(BigInt,MachInt)");
1065     return RoundDiv(num, BigInt(den));
1066   }
1067 
RoundDiv(const MachineInt & num,const BigInt & den)1068   const BigInt RoundDiv(const MachineInt& num, const BigInt& den)
1069   {
1070     if (IsZero(den))
1071       CoCoA_THROW_ERROR(ERR::DivByZero, "RoundDiv(MachInt,BigInt)");
1072     return RoundDiv(BigInt(num), den);
1073   }
1074 
1075   // NB Halves are rounded away from zero.
RoundDiv(const MachineInt & n,const MachineInt & d)1076   long RoundDiv(const MachineInt& n, const MachineInt& d)
1077   {
1078     if (IsZero(d))
1079       CoCoA_THROW_ERROR(ERR::DivByZero, "RoundDiv(n,d)");
1080     if (IsZero(n)) return 0;
1081     // Henceforth n and d are both non-zero.
1082     const long s = sign(n)*sign(d);
1083     const unsigned long q = uround_half_up(uabs(n), uabs(d)); // ROUND AWAY FROM ZERO
1084 //    const unsigned long q = uround_half_down(uabs(n), uabs(d)); // ROUND TOWARDS ZERO
1085     if (s > 0) return NumericCast<long>(q);
1086     static const long MinLong = numeric_limits<long>::min();
1087     if (q + MinLong == 0) return MinLong; // to avoid overflow if result is MinLong.
1088     return -NumericCast<long>(q);
1089 
1090   }
1091 
1092 
FloorRoot(const MachineInt & n,const MachineInt & r)1093   const BigInt FloorRoot(const MachineInt& n, const MachineInt& r)
1094   {
1095     return FloorRoot(BigInt(n), r);
1096   }
1097 
FloorRoot(const MachineInt & n,const BigInt & R)1098   const BigInt FloorRoot(const MachineInt& n, const BigInt& R)
1099   {
1100     if (IsNegative(n))
1101       CoCoA_THROW_ERROR(ERR::NotNonNegative, "FloorRoot: 1st arg must be non-negative");
1102     if (R < 1)
1103       CoCoA_THROW_ERROR(ERR::BadArg, "FloorRoot: 2nd arg must be positive");
1104     unsigned long r;
1105     if (!IsConvertible(r, R))
1106       CoCoA_THROW_ERROR(ERR::ArgTooBig, "FloorRoot: 2nd arg is too big"); // could just return 1???
1107     return FloorRoot(BigInt(n), r);
1108   }
1109 
FloorRoot(const BigInt & N,const MachineInt & r)1110   const BigInt FloorRoot(const BigInt& N, const MachineInt& r)
1111   {
1112     if (N < 0)
1113       CoCoA_THROW_ERROR(ERR::NotNonNegative, "FloorRoot: 1st arg must be non-negative");
1114     if (IsNegative(r) || IsZero(r))
1115       CoCoA_THROW_ERROR(ERR::BadArg, "FloorRoot: 2nd arg must be at least 1");
1116     BigInt ans;
1117     mpz_root(mpzref(ans), mpzref(N), AsUnsignedLong(r));
1118     return ans;
1119   }
1120 
FloorRoot(const BigInt & N,const BigInt & R)1121   const BigInt FloorRoot(const BigInt& N, const BigInt& R)
1122   {
1123     if (N < 0)
1124       CoCoA_THROW_ERROR(ERR::NotNonNegative, "FloorRoot: 1st arg must be non-negative");
1125     if (R < 1)
1126       CoCoA_THROW_ERROR(ERR::BadArg, "FloorRoot: 2nd arg must be at least 1");
1127     unsigned long r;
1128     if (!IsConvertible(r, R))
1129       CoCoA_THROW_ERROR(ERR::ArgTooBig, "FloorRoot: 2nd arg is too big"); // could just return 1???
1130     return FloorRoot(N, r);
1131   }
1132 
1133 
IsExactFloorRoot(long & ans,const MachineInt & n,const MachineInt & r)1134   bool IsExactFloorRoot(long& ans, const MachineInt& n, const MachineInt& r)
1135   {
1136     BigInt root;
1137     const bool IsExact = IsExactFloorRoot(root, BigInt(n), r);
1138     if (!IsConvertible(ans, root))
1139       CoCoA_THROW_ERROR(ERR::ArgTooBig, "IsExactFloorRoot");
1140     return IsExact;
1141   }
1142 
IsExactFloorRoot(BigInt & ans,const MachineInt & n,const MachineInt & r)1143   bool IsExactFloorRoot(BigInt& ans, const MachineInt& n, const MachineInt& r)
1144   {
1145     return IsExactFloorRoot(ans, BigInt(n), r);
1146   }
1147 
IsExactFloorRoot(long & ans,const MachineInt & n,const BigInt & R)1148   bool IsExactFloorRoot(long& ans, const MachineInt& n, const BigInt& R)
1149   {
1150 //    if (IsNegative(n))
1151 //      CoCoA_THROW_ERROR(ERR::NotNonNegative, "IsExactFloorRoot: 1st arg must be non-negative");
1152     unsigned long r;
1153     if (!IsConvertible(r, R))
1154       CoCoA_THROW_ERROR(ERR::ArgTooBig, "IsExactFloorRoot: root index must be >=1 & fit into a ulong");
1155     BigInt root;
1156     const bool IsExact = IsExactFloorRoot(root, BigInt(n), r);
1157     if (!IsConvertible(ans, root))
1158       CoCoA_THROW_ERROR(ERR::ArgTooBig, "IsExactFloorRoot");
1159     return IsExact;
1160   }
1161 
IsExactFloorRoot(BigInt & ans,const MachineInt & n,const BigInt & R)1162   bool IsExactFloorRoot(BigInt& ans, const MachineInt& n, const BigInt& R)
1163   {
1164     unsigned long r;
1165     if (!IsConvertible(r, R))
1166       CoCoA_THROW_ERROR(ERR::ArgTooBig, "IsExactFloorRoot: root index must be >=1 & fit into a ulong");
1167     return IsExactFloorRoot(ans, BigInt(n), r);
1168   }
1169 
IsExactFloorRoot(BigInt & ans,const BigInt & N,const MachineInt & r)1170   bool IsExactFloorRoot(BigInt& ans, const BigInt& N, const MachineInt& r)
1171   {
1172     if (N < 0)
1173       CoCoA_THROW_ERROR(ERR::NotNonNegative, "IsExactFloorRoot: 1st arg must be non-negative");
1174     if (IsNegative(r) || IsZero(r))
1175       CoCoA_THROW_ERROR(ERR::BadArg, "IsExactFloorRoot: root index must be at least 1");
1176 //    if (N < 0 && IsEven(AsUnsignedLong(r)))
1177 //      CoCoA_THROW_ERROR(ERR::BadArg, "IsExactFloorRoot: even root of negative number");
1178     const bool IsExact = mpz_root(mpzref(ans), mpzref(N), AsUnsignedLong(r));
1179     return IsExact;
1180   }
1181 
IsExactFloorRoot(BigInt & ans,const BigInt & N,const BigInt & R)1182   bool IsExactFloorRoot(BigInt& ans, const BigInt& N, const BigInt& R)
1183   {
1184     unsigned long r;
1185     if (!IsConvertible(r, R))
1186       CoCoA_THROW_ERROR(ERR::ArgTooBig, "IsExactFloorRoot: root index must be >=1 & fit into a ulong");
1187     return IsExactFloorRoot(ans, N, r);
1188   }
1189 
1190 
FloorSqrt(const MachineInt & n)1191   long FloorSqrt(const MachineInt& n)
1192   {
1193     if (IsNegative(n)) CoCoA_THROW_ERROR(ERR::NotNonNegative, "FloorSqrt(n)");
1194     return ConvertTo<long>(FloorSqrt(BigInt(n))); // conversion will succeed.
1195     // long ans;
1196     // IsConvertible(ans, FloorSqrt(BigInt(n))); // conversion will succeed.
1197     // return ans;
1198   }
1199 
FloorSqrt(const BigInt & N)1200   const BigInt FloorSqrt(const BigInt& N)
1201   {
1202     if (N < 0) CoCoA_THROW_ERROR(ERR::NotNonNegative, "FloorSqrt(N)");
1203     BigInt ans;
1204     mpz_sqrt(mpzref(ans), mpzref(N));
1205     return ans;
1206   }
1207 
1208 
IsSquare(const MachineInt & n)1209   bool IsSquare(const MachineInt& n)
1210   {
1211     return IsSquare(BigInt(n));
1212   }
1213 
IsSquare(const BigInt & N)1214   bool IsSquare(const BigInt& N)
1215   {
1216     return mpz_perfect_square_p(mpzref(N));
1217   }
1218 
1219 
IsPower(const MachineInt & n)1220   bool IsPower(const MachineInt& n)
1221   {
1222     return IsPower(BigInt(n));
1223   }
1224 
IsPower(const BigInt & N)1225   bool IsPower(const BigInt& N)
1226   {
1227     return mpz_perfect_power_p(mpzref(N));
1228   }
1229 
1230 
1231 } // end of namespace CoCoA
1232 
1233 
1234 // RCS header/log in the next few lines
1235 // $Header: /Volumes/Home_1/cocoa/cvs-repository/CoCoALib-0.99/src/AlgebraicCore/BigIntOps.C,v 1.4 2020/10/06 19:14:30 abbott Exp $
1236 // $Log: BigIntOps.C,v $
1237 // Revision 1.4  2020/10/06 19:14:30  abbott
1238 // Summary: SmallPower now handles some simple case specially (incl power of -1)
1239 //
1240 // Revision 1.3  2020/06/17 15:49:21  abbott
1241 // Summary: Changed CoCoA_ERROR into CoCoA_THROW_ERROR
1242 //
1243 // Revision 1.2  2019/09/16 14:30:34  abbott
1244 // Summary: Changed iroot -> FloorRoot, IsEactIroot -> IsExactFloorRoot; added primorial
1245 //
1246 // Revision 1.1  2018/05/18 12:09:25  bigatti
1247 // -- renamed IntOperations --> BigIntOps
1248 //
1249 // Revision 1.20  2017/11/29 20:30:17  abbott
1250 // Summary: Added MultiplicityOf2C
1251 //
1252 // Revision 1.19  2017/10/16 14:48:05  abbott
1253 // Summary: Corrected internal conversion to long (was unsigned long) in fibonacci
1254 //
1255 // Revision 1.18  2017/02/08 17:01:26  abbott
1256 // Summary: Made uround_half_up and uround-half-down inline
1257 //
1258 // Revision 1.17  2016/08/02 12:49:34  abbott
1259 // Summary: Renamed NumDigits to SizeInBase; updated doc.
1260 //
1261 // Revision 1.16  2015/11/24 12:47:35  abbott
1262 // Summary: Renamed "isqrt" --> "FloorSqrt"
1263 //
1264 // Revision 1.15  2015/11/23 18:21:52  abbott
1265 // Summary: Renamed ILogBase -> FloorLogBase; added FloorLog2, FloorLog10
1266 //
1267 // Revision 1.14  2015/11/05 14:20:06  abbott
1268 // Summary: Changed rtn type of LeastNonNegRemainder to long when modulus is MachineInt
1269 //
1270 // Revision 1.13  2015/10/09 18:26:36  abbott
1271 // Summary: Corrected redmine reference
1272 //
1273 // Revision 1.12  2015/10/09 18:18:27  abbott
1274 // Summary: Renamed "abs" to "uabs" for MachineInt; new fn "negate"; see redmine 783
1275 //
1276 // Revision 1.11  2014/05/16 14:15:29  abbott
1277 // Summary: Rewrote DoundDiv for MachineInts to handle rounding away from zero correctly when result is MinLong
1278 // Author: JAA
1279 //
1280 // Revision 1.10  2014/05/16 12:26:11  abbott
1281 // Summary: Changed rounding (in RoundDiv): it is now "away from zero"
1282 // Author: JAA
1283 //
1284 // Revision 1.9  2014/05/05 18:21:00  abbott
1285 // Removed another M_PI (replaced by 4*atan(1.0))
1286 //
1287 // Revision 1.8  2014/04/30 16:08:42  abbott
1288 // Summary: Removed dependency on nonstd M_PI; now uses atan; cast arg of log to double
1289 // Author: JAA
1290 //
1291 // Revision 1.7  2014/04/10 15:30:33  abbott
1292 // Summary: Corrected impl of IsPowerOf2
1293 // Author: JAA
1294 //
1295 // Revision 1.6  2014/04/08 13:04:13  abbott
1296 // Summary: Added new fn IsPowerOf2
1297 // Author: JAA
1298 //
1299 // Revision 1.5  2014/03/06 15:49:30  abbott
1300 // Summary: Zero to power zero now gives 1
1301 // Author: JAA
1302 //
1303 // Revision 1.4  2013/05/20 15:48:13  abbott
1304 // Added new fn LogFactorial (placed in IntOperations).
1305 //
1306 // Revision 1.3  2013/05/14 14:23:00  abbott
1307 // Minor improvement to log(BigInt)
1308 //
1309 // Revision 1.2  2012/12/04 09:55:47  abbott
1310 // Added new fns LeastNNegRemainder and SymmRemainder (with doc & new test).
1311 // Some minor corrections to the doc (for operator/ and operator%).
1312 //
1313 // Revision 1.1  2012/05/28 09:18:21  abbott
1314 // Created IntOperations which gathers together all operations on
1315 // integers (both big and small).  Many consequential changes.
1316 //
1317 //
1318