1 /*
2  * Normaliz
3  * Copyright (C) 2007-2021  W. Bruns, B. Ichim, Ch. Soeger, U. v. d. Ohe
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  * As an exception, when this program is distributed through (i) the App Store
18  * by Apple Inc.; (ii) the Mac App Store by Apple Inc.; or (iii) Google Play
19  * by Google Inc., then that store may impose any digital rights management,
20  * device limits and/or redistribution restrictions that are required by its
21  * terms of service.
22  */
23 
24 #ifndef LIBNORMALIZ_INTEGER_H_
25 #define LIBNORMALIZ_INTEGER_H_
26 
27 #include <list>
28 #include <vector>
29 #include <string>
30 #include <climits>
31 #include <cmath>
32 #include <iosfwd>
33 
34 #include <libnormaliz/general.h>
35 
36 // Integer should (may) support:
37 // Integer abs(Integer); here implemented as Iabs
38 // Integer min(Integer, Integer); here we use the template min in <algorithm>
39 // It provides abs, gcd and lcm
40 //---------------------------------------------------------------------------
41 
42 namespace libnormaliz {
43 
44 using std::cerr;
45 using std::endl;
46 using std::istream;
47 using std::ostream;
48 using std::ostringstream;
49 using std::string;
50 using std::stringstream;
51 using std::vector;
52 using std::ws;
53 
54 //---------------------------------------------------------------------------
55 //                     Basic functions
56 //---------------------------------------------------------------------------
57 
58 // returns the absolute value of a
59 template <typename Integer>
Iabs(const Integer & a)60 inline Integer Iabs(const Integer& a) {
61     return (a >= 0) ? (a) : Integer(-a);
62 }
63 
64 // returns gcd of a and b,   if one is 0 returns the other integer
65 template <typename Integer>
66 Integer gcd(const Integer& a, const Integer& b);
67 template <>
68 mpz_class gcd<mpz_class>(const mpz_class& a, const mpz_class& b);
69 
70 // returns lcm of a and b,   returns 0 if one is 0
71 template <typename Integer>
72 Integer lcm(const Integer& a, const Integer& b);
73 template <>
74 mpz_class lcm(const mpz_class& a, const mpz_class& b);
75 
76 // integer division a/b. Returns quot and rem = minimal remainder <= |b|/2
77 template <typename Integer>
78 void minimal_remainder(const Integer& a, const Integer& b, Integer& quot, Integer& rem);
79 
80 // extended Euclidean algorithm: d=ua+vb
81 template <typename Integer>
82 Integer ext_gcd(const Integer& a, const Integer& b, Integer& u, Integer& v);
83 
84 // minimizes u and v and makes d >= 0.
85 template <typename Integer>
86 void sign_adjust_and_minimize(const Integer& a, const Integer& b, Integer& d, Integer& u, Integer& v);
87 
88 // the following functions behave like the C++ floating point functions with the same name
89 mpz_class floor(const mpq_class& q);
90 mpz_class ceil(const mpq_class& q);
91 mpz_class round(const mpq_class& q);
92 
93 //---------------------------------------------------------------------------
94 //                     Conversions and checks
95 //---------------------------------------------------------------------------
96 
97 // convert val to ret
98 // does the conversion and returns false if it fails
99 bool try_convert(long& ret, const long long& val);
try_convert(long long & ret,const long & val)100 inline bool try_convert(long long& ret, const long& val) {
101     ret = val;
102     return true;
103 }
104 bool try_convert(long& ret, const mpz_class& val);
105 bool try_convert(long long& ret, const mpz_class& val);
try_convert(mpz_class & ret,const long & val)106 inline bool try_convert(mpz_class& ret, const long& val) {
107     ret = val;
108     return true;
109 }
110 bool try_convert(mpz_class& ret, const long long& val);
111 
112 bool try_convert(nmz_float& ret, const long& val);
113 bool try_convert(nmz_float& ret, const long long& val);
114 bool try_convert(nmz_float& ret, const mpz_class& val);
115 
116 bool try_convert(long& ret, const nmz_float& val);
117 bool try_convert(long long& ret, const nmz_float& val);
118 bool try_convert(mpz_class& ret, const nmz_float& val);
119 
120 nmz_float mpq_to_nmz_float(const mpq_class& val);
121 
122 #ifdef ENFNORMALIZ
123 bool try_convert(renf_elem_class& ret, const mpz_class& val);
124 bool try_convert(mpz_class& ret, const renf_elem_class& val);
125 bool try_convert(renf_elem_class& ret, const long long& val);
126 bool try_convert(long long& ret, const renf_elem_class& val);
127 bool try_convert(renf_elem_class& ret, const long& val);
128 bool try_convert(long& ret, const renf_elem_class& val);
129 bool try_convert(mpq_class& ret, const renf_elem_class& val);
130 bool try_convert(nmz_float& ret, const renf_elem_class& val);
131 #endif
132 
133 // template for same type "conversion"
134 template <typename Type>
try_convert(Type & ret,const Type & val)135 inline bool try_convert(Type& ret, const Type& val) {
136     ret = val;
137     return true;
138 }
139 
try_convert(nmz_float & ret,const nmz_float & val)140 inline bool try_convert(nmz_float& ret, const nmz_float& val) {
141     ret = val;
142     return true;
143 }
144 
145 bool fits_long_range(long long a);
146 
147 //--------------------------------------------------------------------
148 template <typename Integer>
using_GMP()149 inline bool using_GMP() {
150     return false;
151 }
152 
153 template <>
154 inline bool using_GMP<mpz_class>() {
155     return true;
156 }
157 
158 template <>
159 inline bool using_GMP<mpq_class>() {
160     return true;
161 }
162 
163 template <typename Integer>
using_mpq_class()164 inline bool using_mpq_class() {
165     return false;
166 }
167 
168 template <>
169 inline bool using_mpq_class<mpq_class>() {
170     return true;
171 }
172 //--------------------------------------------------------------------
173 
174 template <typename Integer>
using_float()175 inline bool using_float() {
176     return false;
177 }
178 
179 template <>
180 inline bool using_float<nmz_float>() {
181     return true;
182 }
183 
184 //--------------------------------------------------------------------
185 
186 template <typename Number>
using_renf()187 inline bool using_renf() {
188     return false;
189 }
190 
191 #ifdef ENFNORMALIZ
192 template <>
193 inline bool using_renf<renf_elem_class>() {
194     return true;
195 }
196 #endif
197 
198 //--------------------------------------------------------------------
199 
200 // for the interpretation of a string as a decimal fraction or floating point number
201 mpq_class dec_fraction_to_mpq(std::string s);
202 
203 //--------------------------------------------------------------------
204 
205 template <typename Integer>
206 Integer int_max_value_dual();
207 
208 template <typename Integer>
209 Integer int_max_value_primary();
210 
211 //---------------------------------------------------------------------------
212 
213 /*template<typename Integer>
214 inline bool is_scalar_zero(const Integer& m){
215     return m==0;
216 }
217 
218 template<>
219 inline bool is_scalar_zero<nmz_float>(const nmz_float& m){
220     return (Iabs(m) < 1000000.0*nmz_epsilon);
221 }*/
222 
223 template <typename Integer>
check_range(const Integer & m)224 inline bool check_range(const Integer& m) {
225     const Integer max_primary = int_max_value_primary<Integer>();
226     return (Iabs(m) <= max_primary);
227 }
228 
229 template <>
230 inline bool check_range<mpz_class>(const mpz_class& m) {
231     return true;
232 }
233 
234 template <>
235 inline bool check_range<nmz_float>(const nmz_float& m) {
236     return true;
237 }
238 
239 template <>
240 inline bool check_range<mpq_class>(const mpq_class& m) {
241     return true;
242 }
243 
244 #ifdef ENFNORMALIZ
245 template <>
246 inline bool check_range<renf_elem_class>(const renf_elem_class& m) {
247     return true;
248 }
249 #endif
250 //---------------------------------------------------------------------------
251 
252 template <typename Integer>
253 void check_range_list(const std::list<std::vector<Integer> >& ll);
254 
255 template <typename Integer>
256 class CandidateList;
257 template <typename Integer>
258 class Candidate;
259 
260 template <typename Integer>
261 void check_range_list(const CandidateList<Integer>& ll);
262 template <typename Integer>
263 void check_range_list(const std::list<Candidate<Integer> >& ll);
264 
265 //---------------------------------------------------------------------------
266 //                     String conversion functions
267 //---------------------------------------------------------------------------
268 
269 // forward declaration to silence clang error:
270 // 'operator<<' should be declared prior to the call site or in the global namespace
271 template <typename T>
272 std::ostream& operator<<(std::ostream& out, const vector<T>& vec);
273 
274 template <typename Integer>
toString(Integer a)275 string toString(Integer a) {
276     ostringstream ostream;
277     ostream << a;
278     return ostream.str();
279 }
280 template <>
toString(mpz_class a)281 inline string toString(mpz_class a) {
282     return a.get_str();
283 }
284 template <>
toString(mpq_class a)285 inline string toString(mpq_class a) {
286     return a.get_str();
287 }
288 
289 //----------------------------------------------------------------------
290 // the next functions produce an integer quotient of absolute values and determine whether
291 // there is a remainder
292 
293 bool int_quotient(long long& Quot, const mpz_class& Num, const mpz_class& Den);
294 bool int_quotient(long& Quot, const long& Num, const long& Den);
295 bool int_quotient(long long& Quot, const long long& Num, const long long& Den);
296 bool int_quotient(mpz_class& Quot, const mpz_class& Num, const mpz_class& Den);
297 template <typename IntegerRet>
298 bool int_quotient(IntegerRet& Quot, const nmz_float& Num, const nmz_float& Den);
299 
300 // find the floor and ceol of Num/Den
301 template <typename IntegerRet, typename IntegerVal>
302 IntegerRet floor_quot(const IntegerVal Num, IntegerVal Den);
303 
304 template <typename IntegerRet, typename IntegerVal>
305 IntegerRet ceil_quot(const IntegerVal Num, IntegerVal Den);
306 
307 //---------------------------------------------------------------------------
308 template <typename Integer>
minimal_remainder(const Integer & a,const Integer & b,Integer & quot,Integer & rem)309 void minimal_remainder(const Integer& a, const Integer& b, Integer& quot, Integer& rem) {
310     quot = a / b;
311     rem = a - quot * b;
312     if (rem == 0)
313         return;
314     Integer test = 2 * Iabs(rem) - Iabs(b);
315     if (test > 0) {
316         if ((rem < 0 && b > 0) || (rem > 0 && b < 0)) {
317             rem += b;
318             quot--;
319         }
320         else {
321             rem -= b;
322             quot++;
323         }
324     }
325     if (test == 0 && rem < 0) {
326         rem = -rem;
327         if (b > 0)
328             quot--;
329         else
330             quot++;
331     }
332 }
333 
334 template <typename Integer>
sign_adjust_and_minimize(const Integer & a,const Integer & b,Integer & d,Integer & u,Integer & v)335 void sign_adjust_and_minimize(const Integer& a, const Integer& b, Integer& d, Integer& u, Integer& v) {
336     if (d < 0) {
337         d = -d;
338         u = -u;
339         v = -v;
340     }
341     // cout << u << " " << v << endl;
342     if (b == 0)
343         return;
344 
345     Integer sign = 1;
346     if (a < 0)
347         sign = -1;
348     Integer u1 = (sign * u) % (Iabs(b) / d);
349     if (u1 == 0)
350         u1 += Iabs(b) / d;
351     u = sign * u1;
352     v = (d - a * u) / b;
353 }
354 
355 template <typename Integer>
ext_gcd(const Integer & a,const Integer & b,Integer & u,Integer & v)356 Integer ext_gcd(const Integer& a, const Integer& b, Integer& u, Integer& v) {
357     u = 1;
358     v = 0;
359     Integer d = a;
360     if (b == 0) {
361         sign_adjust_and_minimize(a, b, d, u, v);
362         return (d);
363     }
364     Integer v1 = 0;
365     Integer v3 = b;
366     Integer q, t1, t3;
367     while (v3 != 0) {
368         q = d / v3;
369         t3 = d - q * v3;
370         t1 = u - q * v1;
371         u = v1;
372         d = v3;
373         v1 = t1;
374         v3 = t3;
375     }
376     sign_adjust_and_minimize(a, b, d, u, v);
377     return (d);
378 }
379 
380 template <typename Integer>
decimal_length(Integer a)381 size_t decimal_length(Integer a) {
382     ostringstream test;
383     test << a;
384     return test.str().size();
385 }
386 
387 //---------------------------------------------------------------------------
388 //                     Special functions
389 //---------------------------------------------------------------------------
390 
391 // return the number of decimals, needed to write the Integer a
392 template <typename Integer>
393 size_t decimal_length(Integer a);
394 
395 template <typename Integer>
396 mpz_class nmz_factorial(Integer n);
397 
398 //---------------------------------------------------------------------------
399 //                     Input
400 //---------------------------------------------------------------------------
401 
mpq_read(istream & in)402 inline mpq_class mpq_read(istream& in) {
403     const string numeric = "+-0123456789/.e";
404     in >> std::ws;
405     string s;
406     char c;
407     bool is_float = false;
408     while (in.good()) {
409         c = in.peek();
410         size_t pos = numeric.find(c);
411         if (pos == string::npos)
412             break;
413         if (pos > 12)
414             is_float = true;
415         in >> c;
416         s += c;
417     }
418 
419     if (s == "") {
420         string t;
421         t += c;
422         throw BadInputException("Empty number string preceding character " + t +
423                                 ". Most likely mismatch of amb_space and matrix format or forgotten keyword.");
424     }
425 
426     // cout << "t " << s << " f " << is_float << endl;
427 
428     if (s[0] == '+')
429         s = s.substr(1);  // must suppress + sign for mpq_class
430 
431     try {
432         if (!is_float) {
433             return mpq_class(s);
434         }
435         else
436             return dec_fraction_to_mpq(s);
437     } catch (const std::exception& e) {
438         cerr << e.what() << endl;
439         throw BadInputException("Illegal number string " + s + " in input, Exiting.");
440     }
441 }
442 
443 // To be used in input.cpp
string2coeff(mpq_class & coeff,istream & in,const string & s)444 inline void string2coeff(mpq_class& coeff, istream& in, const string& s) {  // in here superfluous parameter
445 
446     stringstream sin(s);
447     coeff = mpq_read(sin);
448     // coeff=mpq_class(s);
449 }
450 
451 // To be used from other sources
string2coeff(mpq_class & coeff,const string & s)452 inline void string2coeff(mpq_class& coeff, const string& s) {
453 
454     // cout << "SSSSSS " << s << endl;
455 
456     const string numeric = "+-0123456789/.e "; // must allow blank
457     for(auto& c: s){
458         size_t pos = numeric.find(c);
459         if(pos == string::npos)
460             throw BadInputException("Illegal character in numerical string");
461     }
462 
463 
464     stringstream sin(s);
465     coeff = mpq_read(sin);
466     // coeff=mpq_class(s);
467 }
468 
read_number(istream & in,mpq_class & number)469 inline void read_number(istream& in, mpq_class& number) {
470     number = mpq_read(in);
471 }
472 
read_number(istream & in,long & number)473 inline void read_number(istream& in, long& number) {
474     in >> number;
475 }
476 
read_number(istream & in,long long & number)477 inline void read_number(istream& in, long long& number) {
478     in >> number;
479 }
480 
read_number(istream & in,nmz_float & number)481 inline void read_number(istream& in, nmz_float& number) {
482     in >> number;
483 }
484 
read_number(istream & in,mpz_class & number)485 inline void read_number(istream& in, mpz_class& number) {
486     in >> number;
487 }
488 
489 #ifdef ENFNORMALIZ
490 
string2coeff(renf_elem_class & coeff,istream & in,const string & s)491 inline void string2coeff(renf_elem_class& coeff, istream& in, const string& s) {  // we need in to access the renf
492 
493     try {
494         coeff = renf_elem_class(*renf_class::get_pword(in), s);
495     } catch (const std::exception& e) {
496         cerr << e.what() << endl;
497         throw BadInputException("Illegal number string " + s + " in input, Exiting.");
498     }
499 }
500 
read_number(istream & in,renf_elem_class & number)501 inline void read_number(istream& in, renf_elem_class& number) {
502     // in >> number;
503 
504     char c;
505 
506     in >> ws;
507     c = in.peek();
508     if (c != '(' && c != '\'' && c != '\"') {  // rational number
509         mpq_class rat = mpq_read(in);
510         number = renf_elem_class(rat);
511         return;
512     }
513 
514     // now we have a proper field element
515 
516     in >> c;  // read (
517 
518     string num_string;
519     bool skip = false;
520     while (in.good()) {
521         c = in.peek();
522         if (c == ')' || c == '\'' || c == '\"') {
523             in >> c;
524             break;
525         }
526         if (c == '~' || c == '=' || c == '[')  // skip the approximation
527             skip = true;
528         in.get(c);
529         if (in.fail())
530             throw BadInputException("Error in reading number: field element not terminated");
531         if (!skip)
532             num_string += c;
533     }
534     string2coeff(number, in, num_string);
535 }
536 #endif
537 
538 // formerly conver.h
539 // conversion for integers, throws ArithmeticException if conversion fails
540 template <typename ToType, typename FromType>
convert(ToType & ret,const FromType & val)541 inline void convert(ToType& ret, const FromType& val) {
542     if (!try_convert(ret, val)) {
543         throw ArithmeticException(val);
544     }
545 }
546 
547 // conversion of vectors
548 template <typename ToType, typename FromType>
convert(vector<ToType> & ret_vect,const vector<FromType> & from_vect)549 inline void convert(vector<ToType>& ret_vect, const vector<FromType>& from_vect) {
550     size_t s = from_vect.size();
551     ret_vect.resize(s);
552     for (size_t i = 0; i < s; ++i)
553         convert(ret_vect[i], from_vect[i]);
554 }
555 
556 // general conversion with return, throws ArithmeticException if conversion fails
557 template <typename ToType, typename FromType>
convertTo(const FromType & val)558 ToType convertTo(const FromType& val) {
559     ToType copy;
560     convert(copy, val);
561     return copy;
562 }
563 
564 
try_convert(mpz_class & ret,const mpq_class & val)565 inline bool try_convert(mpz_class& ret, const mpq_class& val) {
566     assert(false);  // must never be used
567     return false;
568 }
569 
try_convert(mpq_class & ret,const mpz_class & val)570 inline bool try_convert(mpq_class& ret, const mpz_class& val) {
571     assert(false);  // must never be used
572     return false;
573 }
574 
575 #ifdef ENFNORMALIZ
try_convert(renf_elem_class & ret,const mpz_class & val)576 inline  bool try_convert(renf_elem_class& ret, const mpz_class& val) {
577     ret = val;
578     return true;
579 }
580 
try_convert(mpz_class & ret,const renf_elem_class & val)581 inline  bool try_convert(mpz_class& ret, const renf_elem_class& val) {
582     renf_elem_class help = val;
583     if (!help.is_integer())
584         throw ArithmeticException("field element cannot be converted to integer");
585     ret = help.num();
586     return true;
587 }
588 
try_convert(renf_elem_class & ret,const long long & val)589 inline bool try_convert(renf_elem_class& ret, const long long& val) {
590     ret = convertTo<long>(val);
591     return true;
592 }
593 
try_convert(long long & ret,const renf_elem_class & val)594 inline bool try_convert(long long& ret, const renf_elem_class& val) {
595     mpz_class bridge;
596     try_convert(bridge, val);
597     return try_convert(ret, bridge);
598 }
599 
try_convert(renf_elem_class & ret,const long & val)600 inline bool try_convert(renf_elem_class& ret, const long& val) {
601     ret = val;
602     return true;
603 }
604 
try_convert(long & ret,const renf_elem_class & val)605 inline bool try_convert(long& ret, const renf_elem_class& val) {
606     mpz_class bridge;
607     try_convert(bridge, val);
608     return try_convert(ret, bridge);
609 }
610 
try_convert(mpq_class & ret,const renf_elem_class & val)611 inline bool try_convert(mpq_class& ret, const renf_elem_class& val) {
612     nmz_float ret_double = static_cast<double>(val);
613     ret = mpq_class(ret_double);
614     return true;
615 }
616 
try_convert(nmz_float & ret,const renf_elem_class & val)617 inline bool try_convert(nmz_float& ret, const renf_elem_class& val) {
618     ret = static_cast<double>(val);
619     return true;
620 }
621 #endif
622 
try_convert(long & ret,const long long & val)623 inline bool try_convert(long& ret, const long long& val) {
624     if (fits_long_range(val)) {
625         ret = val;
626         return true;
627     }
628     return false;
629 }
630 
try_convert(long & ret,const mpz_class & val)631 inline bool try_convert(long& ret, const mpz_class& val) {
632     if (!val.fits_slong_p()) {
633         return false;
634     }
635     ret = val.get_si();
636     return true;
637 }
638 
try_convert(long long & ret,const mpz_class & val)639 inline bool try_convert(long long& ret, const mpz_class& val) {
640     if (val.fits_slong_p()) {
641         ret = val.get_si();
642         return true;
643     }
644     if (sizeof(long long) == sizeof(long)) {
645         return false;
646     }
647     mpz_class quot;
648     ret = mpz_fdiv_q_ui(quot.get_mpz_t(), val.get_mpz_t(), LONG_MAX);  // returns remainder
649     if (!quot.fits_slong_p()) {
650         return false;
651     }
652     ret += ((long long)quot.get_si()) * ((long long)LONG_MAX);
653     return true;
654 }
655 
try_convert(mpz_class & ret,const long long & val)656 inline bool try_convert(mpz_class& ret, const long long& val) {
657     if (fits_long_range(val)) {
658         ret = mpz_class(long(val));
659     }
660     else {
661         ret = mpz_class(long(val % LONG_MAX)) + mpz_class(LONG_MAX) * mpz_class(long(val / LONG_MAX));
662     }
663     return true;
664 }
665 
try_convert(float & ret,const mpz_class & val)666 inline bool try_convert(float& ret, const mpz_class& val) {
667     if (!val.fits_slong_p())
668         return false;
669     long dummy = convertTo<long>(val);
670     ret = (float)dummy;
671     return true;
672 }
673 
fits_long_range(long long a)674 inline bool fits_long_range(long long a) {
675     return sizeof(long long) == sizeof(long) || (a <= LONG_MAX && a >= LONG_MIN);
676 }
677 
try_convert(nmz_float & ret,const long & val)678 inline bool try_convert(nmz_float& ret, const long& val) {
679     ret = (nmz_float)val;
680     return true;
681 }
682 
try_convert(nmz_float & ret,const mpz_class & val)683 inline bool try_convert(nmz_float& ret, const mpz_class& val) {
684     ret = val.get_d();
685     return true;
686 }
687 
try_convert(mpz_class & ret,const nmz_float & val)688 inline bool try_convert(mpz_class& ret, const nmz_float& val) {
689     ret = mpz_class(val);
690     return true;
691 }
692 
try_convert(nmz_float & ret,const long long & val)693 inline bool try_convert(nmz_float& ret, const long long& val) {
694     ret = (nmz_float)val;
695     return true;
696 }
697 
try_convert(long & ret,const nmz_float & val)698 inline bool try_convert(long& ret, const nmz_float& val) {
699     mpz_class bridge;
700     if (!try_convert(bridge, val))
701         return false;
702     return try_convert(ret, bridge);
703 }
704 
try_convert(long long & ret,const nmz_float & val)705 inline bool try_convert(long long& ret, const nmz_float& val) {
706     mpz_class bridge;
707     if (!try_convert(bridge, val))
708         return false;
709     return try_convert(ret, bridge);
710 }
711 //---------------------------------------------------------------------------
712 
713 template <typename Integer>
gcd(const Integer & a,const Integer & b)714 Integer gcd(const Integer& a, const Integer& b) {
715     if (a == 0) {
716         return Iabs<Integer>(b);
717     }
718     if (b == 0) {
719         return Iabs<Integer>(a);
720     }
721     Integer q0, q1, r;
722     q0 = Iabs<Integer>(a);
723     r = Iabs<Integer>(b);
724     do {
725         q1 = r;
726         r = q0 % q1;
727         q0 = q1;
728     } while (r != 0);
729     return q1;
730 }
731 
732 template <>
gcd(const nmz_float & a,const nmz_float & b)733 inline nmz_float gcd(const nmz_float& a, const nmz_float& b) {
734     if (a == 0 && b == 0)
735         return 0;
736     return 1.0;
737 }
738 
739 template <>
gcd(const mpz_class & a,const mpz_class & b)740 inline  mpz_class gcd(const mpz_class& a, const mpz_class& b) {
741     mpz_class g;
742     mpz_gcd(g.get_mpz_t(), a.get_mpz_t(), b.get_mpz_t());
743     return g;
744 }
745 
746 #ifdef ENFNORMALIZ
747 template <>
gcd(const renf_elem_class & a,const renf_elem_class & b)748 inline  renf_elem_class gcd(const renf_elem_class& a, const renf_elem_class& b) {
749     if (a == 0 && b == 0)
750         return 0;
751     return 1;
752 }
753 #endif
754 
755 //---------------------------------------------------------------------------
756 
757 template <typename Integer>
lcm(const Integer & a,const Integer & b)758 Integer lcm(const Integer& a, const Integer& b) {
759     if ((a == 0) || (b == 0)) {
760         return 0;
761     }
762     else
763         return Iabs<Integer>(a * b / gcd<Integer>(a, b));
764 }
765 
766 template <>
767 inline  mpz_class lcm<mpz_class>(const mpz_class& a, const mpz_class& b) {
768     mpz_class g;
769     mpz_lcm(g.get_mpz_t(), a.get_mpz_t(), b.get_mpz_t());
770     return g;
771 }
772 
773 #ifdef ENFNORMALIZ
774 template <>
775 inline renf_elem_class lcm<renf_elem_class>(const renf_elem_class& a, const renf_elem_class& b) {
776     return 1;
777 }
778 #endif
779 
780 //---------------------------------------------------------------------------
781 
782 template <typename Integer>
int_max_value_dual()783 Integer int_max_value_dual() {
784     Integer k = sizeof(Integer) * 8 - 2;  // number of bytes convetred to number of bits
785     Integer test = 1;
786     test = test << k;  // 2^k
787     return test;
788 }
789 
790 // bool int_max_value_dual_long_computed = false;
791 
792 template <>
int_max_value_dual()793 inline  long int_max_value_dual() {
794     static long max_value;
795 
796     if (int_max_value_dual_long_computed)
797         return max_value;
798 
799     long k = sizeof(long) * 8 - 2;  // number of bytes convetred to number of bits
800     long test = 1;
801     test = test << k;  // 2^k
802     // test=0; // 10000;
803     max_value = test;
804     int_max_value_dual_long_computed = true;
805     return test;
806 }
807 
808 // bool int_max_value_dual_long_long_computed = false;
809 
810 template <>
int_max_value_dual()811 inline  long long int_max_value_dual() {
812     static long long max_value;
813 
814     if (int_max_value_dual_long_long_computed)
815         return max_value;
816 
817     long long k = sizeof(long long) * 8 - 2;  // number of bytes convetred to number of bits
818     long long test = 1;
819     test = test << k;  // 2^k
820     // test=0; // 10000;
821     max_value = test;
822     int_max_value_dual_long_long_computed = true;
823     return test;
824 }
825 
826 //---------------------------------------------------------------------------
827 
828 template <>
829 inline  mpz_class int_max_value_dual<mpz_class>() {
830     assert(false);
831     return 0;
832 }
833 
834 //---------------------------------------------------------------------------
835 
836 template <typename Integer>
int_max_value_primary()837 Integer int_max_value_primary() {
838     Integer k = sizeof(Integer) * 8 - 12;  // number of bytes convetred to number of bits
839     Integer test = 1;
840     test = test << k;  // 2^k
841     // test=0; // 10000;
842     return test;
843 }
844 
845 // bool int_max_value_primary_long_computed = false;
846 
847 template <>
int_max_value_primary()848 inline  long int_max_value_primary() {
849     static long max_value;
850 
851     if (int_max_value_primary_long_computed)
852         return max_value;
853 
854     long k = sizeof(long) * 8 - 12;  // number of bytes convetred to number of bits
855     long test = 1;
856     test = test << k;  // 2^k
857     // test=0; // 10000;
858     int_max_value_primary_long_computed = true;
859     max_value = test;
860     return test;
861 }
862 
863 // bool int_max_value_primary_long_long_computed = false;
864 
865 template <>
int_max_value_primary()866 inline  long long int_max_value_primary() {
867     static long long max_value;
868 
869     if (int_max_value_primary_long_long_computed)
870         return max_value;
871 
872     long long k = sizeof(long long) * 8 - 12;  // number of bytes convetred to number of bits
873     long long test = 1;
874     test = test << k;  // 2^k
875 #ifdef NMZ_EXTENDED_TESTS
876     if(test_linear_algebra_GMP)
877         test=0;
878 #endif
879     max_value = test;
880     int_max_value_primary_long_long_computed = true;
881     return test;
882 }
883 
884 //---------------------------------------------------------------------------
885 
886 template <>
887 inline  mpz_class int_max_value_primary<mpz_class>() {
888     assert(false);
889     return 0;
890 }
891 
892 #ifdef ENFNORMALIZ
893 template <>
894 inline  renf_elem_class int_max_value_primary<renf_elem_class>() {
895     assert(false);
896     return 0;
897 }
898 #endif
899 
900 //---------------------------------------------------------------------------
901 
902 template <typename Integer>
check_range_list(const CandidateList<Integer> & ll)903 void check_range_list(const CandidateList<Integer>& ll) {
904     check_range_list(ll.Candidates);
905 }
906 
907 //---------------------------------------------------------------------------
908 
909 template <typename Integer>
check_range_list(const std::list<Candidate<Integer>> & ll)910 void check_range_list(const std::list<Candidate<Integer> >& ll) {
911     if (using_GMP<Integer>())
912         return;
913 
914     Integer test = int_max_value_dual<Integer>();
915     // cout << "test " << test << endl;
916 
917     for (const auto& v : ll) {
918         for (size_t i = 0; i < v.values.size(); ++i)
919             if (Iabs(v.values[i]) >= test) {
920                 // cout << v;
921                 // cout << "i " << i << " " << Iabs(v[i]) << endl;
922                 throw ArithmeticException("Vector entry out of range. Imminent danger of arithmetic overflow.");
923             }
924     }
925 }
926 
927 //---------------------------------------------------------------------------
928 
dec_fraction_to_mpq(string s)929 inline  mpq_class dec_fraction_to_mpq(string s) {
930     size_t skip = 0;  // skip leading spaces
931     for (; skip < s.size(); ++skip) {
932         if (!isspace(s[skip]))
933             break;
934     }
935     s = s.substr(skip);
936 
937     mpz_class sign = 1;
938     if (s[0] == '+')
939         s = s.substr(1);
940     else if (s[0] == '-') {
941         s = s.substr(1);
942         sign = -1;
943     }
944 
945     if (s[0] == '+' || s[0] == '-')
946         throw BadInputException("Error in decimal fraction " + s);
947 
948     string int_string, frac_string, exp_string;
949     size_t frac_part_length = 0;
950     size_t pos_point = s.find(".");
951     size_t pos_E = s.find("e");
952     if (pos_point != string::npos) {
953         int_string = s.substr(0, pos_point);
954         if (pos_E != string::npos) {
955             frac_part_length = pos_E - (pos_point + 1);
956         }
957         else
958             frac_part_length = s.size() - (pos_point + 1);
959         frac_string = s.substr(pos_point + 1, frac_part_length);
960         if (frac_string[0] == '+' || frac_string[0] == '-')
961             throw BadInputException("Error in decimal fraction " + s);
962     }
963     else
964         int_string = s.substr(0, pos_E);
965     if (pos_E != string::npos)
966         exp_string = s.substr(pos_E + 1, s.size() - (pos_E + 1));
967 
968     /* cout << "int  " << int_string << endl;
969     cout << "frac " << frac_string << endl;
970     cout << "exp  " << exp_string << endl; */
971 
972     // remove leading 0 and +
973     if (int_string.size() > 0 && int_string[0] == '+')
974         int_string = int_string.substr(1);
975     while (int_string.size() > 0 && int_string[0] == '0')
976         int_string = int_string.substr(1);
977     while (frac_string.size() > 0 && frac_string[0] == '0')
978         frac_string = frac_string.substr(1);
979     if (exp_string.size() > 0 && exp_string[0] == '+')
980         exp_string = exp_string.substr(1);
981     bool exponent_could_be_zero=false;
982     while (exp_string.size() > 0 && exp_string[0] == '0'){
983         exponent_could_be_zero = true;
984         exp_string = exp_string.substr(1);
985     }
986 
987     if(pos_E != string::npos &&  exp_string == "" && !exponent_could_be_zero)
988         throw BadInputException("No exponent following character e in floating point number");
989 
990     mpq_class int_part, frac_part, exp_part;
991     if (!int_string.empty())
992         int_part = mpz_class(int_string);
993 
994     if (pos_E == 0)
995         int_part = 1;
996 
997     // cout << "int_part " << int_part << endl;
998 
999     mpz_class den = 1;
1000     if (!frac_string.empty()) {
1001         frac_part = mpz_class(frac_string);
1002         for (size_t i = 0; i < frac_part_length; ++i)
1003             den *= 10;
1004     }
1005     // cout << "frac_part " << frac_part << endl;
1006     mpq_class result = int_part;
1007     if (frac_part != 0)
1008         result += frac_part / den;
1009     if (!exp_string.empty()) {
1010         mpz_class expo(exp_string);  // we take mpz_class because it has better error checking
1011         // long expo=stol(exp_string);
1012         mpz_class abs_expo = Iabs(expo);
1013         mpz_class factor = 1;
1014         for (long i = 0; i < abs_expo; ++i)
1015             factor *= 10;
1016         if (expo >= 0)
1017             result *= factor;
1018         else
1019             result /= factor;
1020     }
1021     /* cout <<" result " << sign*result << endl;
1022     cout << "==========" << endl; */
1023     return sign * result;
1024 }
1025 
1026 //----------------------------------------------------------------------
1027 // the next function produce an integer quotient and determine whether
1028 // there is a remainder
1029 
int_quotient(long & Quot,const long & Num,const long & Den)1030 inline bool int_quotient(long& Quot, const long& Num, const long& Den) {
1031     Quot = Iabs(Num) / Iabs(Den);
1032     return Quot * Iabs(Den) != Iabs(Num);
1033 }
1034 
int_quotient(long long & Quot,const long long & Num,const long long & Den)1035 inline bool int_quotient(long long& Quot, const long long& Num, const long long& Den) {
1036     Quot = Iabs(Num) / Iabs(Den);
1037     return Quot * Iabs(Den) != Iabs(Num);
1038 }
1039 
int_quotient(mpz_class & Quot,const mpz_class & Num,const mpz_class & Den)1040 inline bool int_quotient(mpz_class& Quot, const mpz_class& Num, const mpz_class& Den) {
1041     Quot = Iabs(Num) / Iabs(Den);
1042     return Quot * Iabs(Den) != Iabs(Num);
1043 }
1044 
int_quotient(long long & Quot,const mpz_class & Num,const mpz_class & Den)1045 inline bool int_quotient(long long& Quot, const mpz_class& Num, const mpz_class& Den) {
1046     mpz_class mpz_Quot = (Iabs(Num) / Iabs(Den));
1047     convert(Quot, mpz_Quot);
1048     return mpz_Quot * Iabs(Den) != Iabs(Num);
1049 }
1050 
1051 template <typename IntegerRet>
int_quotient(IntegerRet & Quot,const nmz_float & Num,const nmz_float & Den)1052 inline bool int_quotient(IntegerRet& Quot, const nmz_float& Num, const nmz_float& Den) {
1053     nmz_float FloatQuot = Iabs(Num) / Iabs(Den);         // cout << "FF " << FloatQuot << endl;
1054     nmz_float IntQuot = trunc(FloatQuot + nmz_epsilon);  // cout << "II " << IntQuot << endl;
1055     Quot = convertTo<IntegerRet>(IntQuot);               // cout << "QQ " <<  Quot << endl;
1056     return FloatQuot - IntQuot > nmz_epsilon;
1057 }
1058 
1059 
1060 template <typename IntegerRet, typename IntegerVal>
floor_quot(const IntegerVal Num,IntegerVal Den)1061 IntegerRet floor_quot(const IntegerVal Num, IntegerVal Den) {
1062     IntegerRet Quot;
1063     bool frac = int_quotient(Quot, Num, Den);
1064     if ((Num >= 0 && Den >= 0) || (Num < 0 && Den < 0)) {
1065         return Quot;
1066     }
1067     else {
1068         if (frac) {
1069             return -Quot - 1;
1070         }
1071         return -Quot;
1072     }
1073 }
1074 
1075 template <typename IntegerRet, typename IntegerVal>
ceil_quot(const IntegerVal Num,IntegerVal Den)1076 IntegerRet ceil_quot(const IntegerVal Num, IntegerVal Den) {
1077     IntegerRet Quot;
1078     bool frac = int_quotient(Quot, Num, Den);
1079     if ((Num >= 0 && Den >= 0) || (Num < 0 && Den < 0)) {
1080         if (frac)
1081             return Quot + 1;
1082         return Quot;
1083     }
1084     else {
1085         return -Quot;
1086     }
1087 }
1088 
1089 #ifdef ENFNORMALIZ
1090 template <>
floor_quot(const renf_elem_class Num,renf_elem_class Den)1091 inline mpz_class floor_quot(const renf_elem_class Num, renf_elem_class Den) {
1092     return floor(Num / Den);
1093 }
1094 
1095 template <>
ceil_quot(const renf_elem_class Num,renf_elem_class Den)1096 inline mpz_class ceil_quot(const renf_elem_class Num, renf_elem_class Den) {
1097     return ceil(Num / Den);
1098 }
1099 #endif
1100 
1101 //----------------------------------------------------------------------
1102 
floor(const mpq_class & q)1103 inline mpz_class floor(const mpq_class& q) {
1104     mpz_class num = q.get_num();
1105     mpz_class den = q.get_den();
1106     mpz_class ent = num / den;
1107     if (num < 0 && den * ent != num)
1108         ent--;
1109     return ent;
1110 }
1111 
ceil(const mpq_class & q)1112 inline mpz_class ceil(const mpq_class& q) {
1113     mpz_class num = q.get_num();
1114     mpz_class den = q.get_den();
1115     mpz_class ent = num / den;
1116     if (num > 0 && den * ent != num)
1117         ent++;
1118     return ent;
1119 }
1120 
round(const mpq_class & q)1121 inline  mpz_class round(const mpq_class& q) {
1122     mpq_class work;
1123     if (q >= 0) {
1124         work = q - mpq_class(1, 2);
1125         return ceil(work);
1126     }
1127     work = q + mpq_class(1, 2);
1128     return floor(work);
1129 }
1130 
1131 template <typename Integer>
nmz_factorial(Integer n)1132 mpz_class nmz_factorial(Integer n) {
1133     assert(n >= 0);
1134     mpz_class f = 1;
1135     long nlong = convertTo<long>(n);
1136     for (long i = 1; i <= nlong; ++i)
1137         f *= i;
1138     return f;
1139 }
1140 
1141 
1142 template <typename Integer>
nmz_binomial(Integer n,Integer k)1143 mpz_class nmz_binomial(Integer n, Integer k) {
1144     if (k > n)
1145         return 0;
1146     return nmz_factorial(n) / nmz_factorial(k);
1147 }
1148 
1149 
mpq_to_nmz_float(const mpq_class & val)1150 inline  nmz_float mpq_to_nmz_float(const mpq_class& val) {
1151     mpz_class bound = 1;
1152     for (size_t i = 0; i < 60; ++i)
1153         bound *= 10;
1154     mpz_class gmp_num = val.get_num(), gmp_den = val.get_den();
1155     while (Iabs(gmp_num) > bound && Iabs(gmp_den) > bound) {
1156         gmp_num /= 10;
1157         gmp_den /= 10;
1158     }
1159     nmz_float num, den;
1160     convert(num, gmp_num);
1161     convert(den, gmp_den);
1162     return num / den;
1163 }
1164 
1165 template <typename Integer>
convertToLong(const Integer & val)1166 long convertToLong(const Integer& val){
1167 
1168     long ret;
1169     try{
1170         ret = convertTo<long>(val);
1171     }
1172     catch (const ArithmeticException& e){
1173         throw LongException(val);
1174     }
1175 
1176     return ret;
1177 
1178 }
1179 
1180 template <typename Integer>
convertToLongLong(const Integer & val)1181 long convertToLongLong(const Integer& val){
1182 
1183     long ret;
1184     try{
1185         ret = convertTo<long long>(val);
1186     }
1187     catch (const ArithmeticException& e){
1188         throw LongLongException(val);
1189     }
1190 
1191     return ret;
1192 
1193 }
1194 }  // namespace libnormaliz
1195 
1196 //---------------------------------------------------------------------------
1197 #endif /* INTEGER_H_ */
1198 //---------------------------------------------------------------------------
1199