1 /* Specialized "checked" functions for GMP's mpz_class numbers.
2    Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it>
3    Copyright (C) 2010-2016 BUGSENG srl (http://bugseng.com)
4 
5 This file is part of the Parma Polyhedra Library (PPL).
6 
7 The PPL is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 The PPL is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software Foundation,
19 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.
20 
21 For the most up-to-date information see the Parma Polyhedra Library
22 site: http://bugseng.com/products/ppl/ . */
23 
24 #ifndef PPL_checked_mpz_inlines_hh
25 #define PPL_checked_mpz_inlines_hh 1
26 
27 #include <sstream>
28 
29 namespace Parma_Polyhedra_Library {
30 
31 namespace Checked {
32 
33 template <typename Policy>
34 inline Result
round_lt_mpz(mpz_class & to,Rounding_Dir dir)35 round_lt_mpz(mpz_class& to, Rounding_Dir dir) {
36   if (round_down(dir)) {
37     --to;
38     return V_GT;
39   }
40   return V_LT;
41 }
42 
43 template <typename Policy>
44 inline Result
round_gt_mpz(mpz_class & to,Rounding_Dir dir)45 round_gt_mpz(mpz_class& to, Rounding_Dir dir) {
46   if (round_up(dir)) {
47     ++to;
48     return V_LT;
49   }
50   return V_GT;
51 }
52 
53 #if __cplusplus >= 201103L
54 //! Type of the _mp_size field of GMP's __mpz_struct.
55 typedef decltype(__mpz_struct()._mp_size) mp_size_field_t;
56 #elif PPL_HAVE_TYPEOF
57 //! Type of the _mp_size field of GMP's __mpz_struct.
58 typedef typeof(__mpz_struct()._mp_size) mp_size_field_t;
59 #else
60 //! This is assumed to be the type of the _mp_size field of GMP's __mpz_struct.
61 typedef int mp_size_field_t;
62 #endif
63 
64 inline mp_size_field_t
get_mp_size(const mpz_class & v)65 get_mp_size(const mpz_class &v) {
66   return v.get_mpz_t()->_mp_size;
67 }
68 
69 inline void
set_mp_size(mpz_class & v,mp_size_field_t size)70 set_mp_size(mpz_class &v, mp_size_field_t size) {
71   v.get_mpz_t()->_mp_size = size;
72 }
73 
74 template <typename Policy>
75 inline Result
classify_mpz(const mpz_class & v,bool nan,bool inf,bool sign)76 classify_mpz(const mpz_class& v, bool nan, bool inf, bool sign) {
77   if (Policy::has_nan || Policy::has_infinity) {
78     mp_size_field_t s = get_mp_size(v);
79     if (Policy::has_nan
80         && (nan || sign)
81         && s == C_Integer<mp_size_field_t>::min + 1) {
82       return V_NAN;
83     }
84     if (!inf && !sign) {
85       return V_LGE;
86     }
87     if (Policy::has_infinity) {
88       if (s == C_Integer<mp_size_field_t>::min) {
89         return inf ? V_EQ_MINUS_INFINITY : V_LT;
90       }
91       if (s == C_Integer<mp_size_field_t>::max) {
92         return inf ? V_EQ_PLUS_INFINITY : V_GT;
93       }
94     }
95   }
96   if (sign) {
97     return static_cast<Result>(sgn<Policy>(v));
98   }
99   return V_LGE;
100 }
101 
PPL_SPECIALIZE_CLASSIFY(classify_mpz,mpz_class)102 PPL_SPECIALIZE_CLASSIFY(classify_mpz, mpz_class)
103 
104 template <typename Policy>
105 inline bool
106 is_nan_mpz(const mpz_class& v) {
107   return Policy::has_nan
108     && get_mp_size(v) == C_Integer<mp_size_field_t>::min + 1;
109 }
110 
PPL_SPECIALIZE_IS_NAN(is_nan_mpz,mpz_class)111 PPL_SPECIALIZE_IS_NAN(is_nan_mpz, mpz_class)
112 
113 template <typename Policy>
114 inline bool
115 is_minf_mpz(const mpz_class& v) {
116   return Policy::has_infinity
117     && get_mp_size(v) == C_Integer<mp_size_field_t>::min;
118 }
119 
PPL_SPECIALIZE_IS_MINF(is_minf_mpz,mpz_class)120 PPL_SPECIALIZE_IS_MINF(is_minf_mpz, mpz_class)
121 
122 template <typename Policy>
123 inline bool
124 is_pinf_mpz(const mpz_class& v) {
125   return Policy::has_infinity
126     && get_mp_size(v) == C_Integer<mp_size_field_t>::max;
127 }
128 
PPL_SPECIALIZE_IS_PINF(is_pinf_mpz,mpz_class)129 PPL_SPECIALIZE_IS_PINF(is_pinf_mpz, mpz_class)
130 
131 template <typename Policy>
132 inline bool
133 is_int_mpz(const mpz_class& v) {
134   return !is_nan<Policy>(v);
135 }
136 
PPL_SPECIALIZE_IS_INT(is_int_mpz,mpz_class)137 PPL_SPECIALIZE_IS_INT(is_int_mpz, mpz_class)
138 
139 template <typename Policy>
140 inline Result
141 assign_special_mpz(mpz_class& v, Result_Class c, Rounding_Dir) {
142   switch (c) {
143   case VC_NAN:
144     if (Policy::has_nan) {
145       set_mp_size(v, C_Integer<mp_size_field_t>::min + 1);
146     }
147     return V_NAN;
148   case VC_MINUS_INFINITY:
149     if (Policy::has_infinity) {
150       set_mp_size(v, C_Integer<mp_size_field_t>::min);
151       return V_EQ_MINUS_INFINITY;
152     }
153     return V_EQ_MINUS_INFINITY | V_UNREPRESENTABLE;
154   case VC_PLUS_INFINITY:
155     if (Policy::has_infinity) {
156       set_mp_size(v, C_Integer<mp_size_field_t>::max);
157       return V_EQ_PLUS_INFINITY;
158     }
159     return V_EQ_PLUS_INFINITY | V_UNREPRESENTABLE;
160   default:
161     PPL_UNREACHABLE;
162     return V_NAN;
163   }
164 }
165 
PPL_SPECIALIZE_ASSIGN_SPECIAL(assign_special_mpz,mpz_class)166 PPL_SPECIALIZE_ASSIGN_SPECIAL(assign_special_mpz, mpz_class)
167 
168 template <typename To_Policy, typename From_Policy>
169 inline void
170 copy_mpz(mpz_class& to, const mpz_class& from) {
171   if (is_nan_mpz<From_Policy>(from)) {
172     PPL_ASSERT(To_Policy::has_nan);
173   }
174   else if (is_minf_mpz<From_Policy>(from) || is_pinf_mpz<From_Policy>(from)) {
175     PPL_ASSERT(To_Policy::has_infinity);
176   }
177   else {
178     to = from;
179     return;
180   }
181   set_mp_size(to, get_mp_size(from));
182 }
183 
PPL_SPECIALIZE_COPY(copy_mpz,mpz_class)184 PPL_SPECIALIZE_COPY(copy_mpz, mpz_class)
185 
186 template <typename To_Policy, typename From_Policy, typename From>
187 inline Result
188 construct_mpz_base(mpz_class& to, const From from, Rounding_Dir) {
189     new(&to) mpz_class(from);
190     return V_EQ;
191 }
192 
PPL_SPECIALIZE_CONSTRUCT(construct_mpz_base,mpz_class,char)193 PPL_SPECIALIZE_CONSTRUCT(construct_mpz_base, mpz_class, char)
194 PPL_SPECIALIZE_CONSTRUCT(construct_mpz_base, mpz_class, signed char)
195 PPL_SPECIALIZE_CONSTRUCT(construct_mpz_base, mpz_class, signed short)
196 PPL_SPECIALIZE_CONSTRUCT(construct_mpz_base, mpz_class, signed int)
197 PPL_SPECIALIZE_CONSTRUCT(construct_mpz_base, mpz_class, signed long)
198 PPL_SPECIALIZE_CONSTRUCT(construct_mpz_base, mpz_class, unsigned char)
199 PPL_SPECIALIZE_CONSTRUCT(construct_mpz_base, mpz_class, unsigned short)
200 PPL_SPECIALIZE_CONSTRUCT(construct_mpz_base, mpz_class, unsigned int)
201 PPL_SPECIALIZE_CONSTRUCT(construct_mpz_base, mpz_class, unsigned long)
202 
203 template <typename To_Policy, typename From_Policy, typename From>
204 inline Result
205 construct_mpz_float(mpz_class& to, const From& from, Rounding_Dir dir) {
206   if (is_nan<From_Policy>(from)) {
207     return construct_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
208   }
209   else if (is_minf<From_Policy>(from)) {
210     return construct_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
211   }
212   else if (is_pinf<From_Policy>(from)) {
213     return construct_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
214   }
215   if (round_not_requested(dir)) {
216     new(&to) mpz_class(from);
217     return V_LGE;
218   }
219   From n = rint(from);
220   new(&to) mpz_class(n);
221   if (from == n) {
222     return V_EQ;
223   }
224   if (from < 0) {
225     return round_lt_mpz<To_Policy>(to, dir);
226   }
227   else {
228     return round_gt_mpz<To_Policy>(to, dir);
229   }
230 }
231 
PPL_SPECIALIZE_CONSTRUCT(construct_mpz_float,mpz_class,float)232 PPL_SPECIALIZE_CONSTRUCT(construct_mpz_float, mpz_class, float)
233 PPL_SPECIALIZE_CONSTRUCT(construct_mpz_float, mpz_class, double)
234 
235 PPL_SPECIALIZE_ASSIGN(assign_exact, mpz_class, mpz_class)
236 PPL_SPECIALIZE_ASSIGN(assign_exact, mpz_class, char)
237 PPL_SPECIALIZE_ASSIGN(assign_exact, mpz_class, signed char)
238 PPL_SPECIALIZE_ASSIGN(assign_exact, mpz_class, signed short)
239 PPL_SPECIALIZE_ASSIGN(assign_exact, mpz_class, signed int)
240 PPL_SPECIALIZE_ASSIGN(assign_exact, mpz_class, signed long)
241 PPL_SPECIALIZE_ASSIGN(assign_exact, mpz_class, unsigned char)
242 PPL_SPECIALIZE_ASSIGN(assign_exact, mpz_class, unsigned short)
243 PPL_SPECIALIZE_ASSIGN(assign_exact, mpz_class, unsigned int)
244 PPL_SPECIALIZE_ASSIGN(assign_exact, mpz_class, unsigned long)
245 
246 template <typename To_Policy, typename From_Policy, typename From>
247 inline Result
248 assign_mpz_signed_int(mpz_class& to, const From from, Rounding_Dir) {
249   if (sizeof(From) <= sizeof(signed long)) {
250     to = static_cast<signed long>(from);
251   }
252   else {
253     mpz_ptr m = to.get_mpz_t();
254     if (from >= 0) {
255       mpz_import(m, 1, 1, sizeof(From), 0, 0, &from);
256     }
257     else {
258       From n = -from;
259       mpz_import(m, 1, 1, sizeof(From), 0, 0, &n);
260       mpz_neg(m, m);
261     }
262   }
263   return V_EQ;
264 }
265 
PPL_SPECIALIZE_ASSIGN(assign_mpz_signed_int,mpz_class,signed long long)266 PPL_SPECIALIZE_ASSIGN(assign_mpz_signed_int, mpz_class, signed long long)
267 
268 template <typename To_Policy, typename From_Policy, typename From>
269 inline Result
270 assign_mpz_unsigned_int(mpz_class& to, const From from, Rounding_Dir) {
271   if (sizeof(From) <= sizeof(unsigned long)) {
272     to = static_cast<unsigned long>(from);
273   }
274   else {
275     mpz_import(to.get_mpz_t(), 1, 1, sizeof(From), 0, 0, &from);
276   }
277   return V_EQ;
278 }
279 
PPL_SPECIALIZE_ASSIGN(assign_mpz_unsigned_int,mpz_class,unsigned long long)280 PPL_SPECIALIZE_ASSIGN(assign_mpz_unsigned_int, mpz_class, unsigned long long)
281 
282 template <typename To_Policy, typename From_Policy, typename From>
283 inline Result
284 assign_mpz_float(mpz_class& to, const From from, Rounding_Dir dir) {
285   if (is_nan<From_Policy>(from)) {
286     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
287   }
288   else if (is_minf<From_Policy>(from)) {
289     return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
290   }
291   else if (is_pinf<From_Policy>(from)) {
292     return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
293   }
294   if (round_not_requested(dir)) {
295     to = from;
296     return V_LGE;
297   }
298   From i_from = rint(from);
299   to = i_from;
300   if (from == i_from) {
301     return V_EQ;
302   }
303   if (round_direct(ROUND_UP)) {
304     return round_lt_mpz<To_Policy>(to, dir);
305   }
306   if (round_direct(ROUND_DOWN)) {
307     return round_gt_mpz<To_Policy>(to, dir);
308   }
309   if (from < i_from) {
310     return round_lt_mpz<To_Policy>(to, dir);
311   }
312   if (from > i_from) {
313     return round_gt_mpz<To_Policy>(to, dir);
314   }
315   PPL_UNREACHABLE;
316   return V_NAN;
317 }
318 
PPL_SPECIALIZE_ASSIGN(assign_mpz_float,mpz_class,float)319 PPL_SPECIALIZE_ASSIGN(assign_mpz_float, mpz_class, float)
320 PPL_SPECIALIZE_ASSIGN(assign_mpz_float, mpz_class, double)
321 
322 template <typename To_Policy, typename From_Policy, typename From>
323 inline Result
324 assign_mpz_long_double(mpz_class& to, const From& from, Rounding_Dir dir) {
325   if (is_nan<From_Policy>(from)) {
326     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
327   }
328   else if (is_minf<From_Policy>(from)) {
329     return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
330   }
331   else if (is_pinf<From_Policy>(from)) {
332     return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
333   }
334   // FIXME: this is an incredibly inefficient implementation!
335   std::stringstream ss;
336   output<From_Policy>(ss, from, Numeric_Format(), dir);
337   PPL_DIRTY_TEMP(mpq_class, tmp);
338 #ifndef NDEBUG
339   Result r =
340 #endif
341     input_mpq(tmp, ss);
342   PPL_ASSERT(r == V_EQ);
343   return assign<To_Policy, From_Policy>(to, tmp, dir);
344 }
345 
PPL_SPECIALIZE_ASSIGN(assign_mpz_long_double,mpz_class,long double)346 PPL_SPECIALIZE_ASSIGN(assign_mpz_long_double, mpz_class, long double)
347 
348 template <typename To_Policy, typename From_Policy>
349 inline Result
350 assign_mpz_mpq(mpz_class& to, const mpq_class& from, Rounding_Dir dir) {
351   if (round_not_needed(dir)) {
352     to = from.get_num();
353     return V_LGE;
354   }
355   if (round_ignore(dir)) {
356     to = from;
357     return V_LGE;
358   }
359   const mpz_srcptr n = from.get_num().get_mpz_t();
360   const mpz_srcptr d = from.get_den().get_mpz_t();
361   if (round_down(dir)) {
362     mpz_fdiv_q(to.get_mpz_t(), n, d);
363     if (round_strict_relation(dir)) {
364       return (mpz_divisible_p(n, d) != 0) ? V_EQ : V_GT;
365     }
366     return V_GE;
367   }
368   else {
369     PPL_ASSERT(round_up(dir));
370     mpz_cdiv_q(to.get_mpz_t(), n, d);
371     if (round_strict_relation(dir)) {
372       return (mpz_divisible_p(n, d) != 0) ? V_EQ : V_LT;
373     }
374     return V_LE;
375   }
376 }
377 
PPL_SPECIALIZE_ASSIGN(assign_mpz_mpq,mpz_class,mpq_class)378 PPL_SPECIALIZE_ASSIGN(assign_mpz_mpq, mpz_class, mpq_class)
379 
380 PPL_SPECIALIZE_FLOOR(assign_exact, mpz_class, mpz_class)
381 PPL_SPECIALIZE_CEIL(assign_exact, mpz_class, mpz_class)
382 PPL_SPECIALIZE_TRUNC(assign_exact, mpz_class, mpz_class)
383 
384 template <typename To_Policy, typename From_Policy>
385 inline Result
386 neg_mpz(mpz_class& to, const mpz_class& from, Rounding_Dir) {
387   mpz_neg(to.get_mpz_t(), from.get_mpz_t());
388   return V_EQ;
389 }
390 
PPL_SPECIALIZE_NEG(neg_mpz,mpz_class,mpz_class)391 PPL_SPECIALIZE_NEG(neg_mpz, mpz_class, mpz_class)
392 
393 template <typename To_Policy, typename From1_Policy, typename From2_Policy>
394 inline Result
395 add_mpz(mpz_class& to, const mpz_class& x, const mpz_class& y, Rounding_Dir) {
396   to = x + y;
397   return V_EQ;
398 }
399 
PPL_SPECIALIZE_ADD(add_mpz,mpz_class,mpz_class,mpz_class)400 PPL_SPECIALIZE_ADD(add_mpz, mpz_class, mpz_class, mpz_class)
401 
402 template <typename To_Policy, typename From1_Policy, typename From2_Policy>
403 inline Result
404 sub_mpz(mpz_class& to, const mpz_class& x, const mpz_class& y, Rounding_Dir) {
405   to = x - y;
406   return V_EQ;
407 }
408 
PPL_SPECIALIZE_SUB(sub_mpz,mpz_class,mpz_class,mpz_class)409 PPL_SPECIALIZE_SUB(sub_mpz, mpz_class, mpz_class, mpz_class)
410 
411 template <typename To_Policy, typename From1_Policy, typename From2_Policy>
412 inline Result
413 mul_mpz(mpz_class& to, const mpz_class& x, const mpz_class& y, Rounding_Dir) {
414   to = x * y;
415   return V_EQ;
416 }
417 
PPL_SPECIALIZE_MUL(mul_mpz,mpz_class,mpz_class,mpz_class)418 PPL_SPECIALIZE_MUL(mul_mpz, mpz_class, mpz_class, mpz_class)
419 
420 template <typename To_Policy, typename From1_Policy, typename From2_Policy>
421 inline Result
422 div_mpz(mpz_class& to, const mpz_class& x, const mpz_class& y,
423         Rounding_Dir dir) {
424   if (CHECK_P(To_Policy::check_div_zero, ::sgn(y) == 0)) {
425     return assign_nan<To_Policy>(to, V_DIV_ZERO);
426   }
427   const mpz_srcptr n = x.get_mpz_t();
428   const mpz_srcptr d = y.get_mpz_t();
429   if (round_not_needed(dir)) {
430     mpz_divexact(to.get_mpz_t(), n, d);
431     return V_LGE;
432   }
433   if (round_ignore(dir)) {
434     mpz_cdiv_q(to.get_mpz_t(), n, d);
435     return V_LE;
436   }
437   if (round_down(dir)) {
438     mpz_fdiv_q(to.get_mpz_t(), n, d);
439     if (round_strict_relation(dir)) {
440       return (mpz_divisible_p(n, d) != 0) ? V_EQ : V_GT;
441     }
442     return V_GE;
443   }
444   else {
445     PPL_ASSERT(round_up(dir));
446     mpz_cdiv_q(to.get_mpz_t(), n, d);
447     if (round_strict_relation(dir)) {
448       return (mpz_divisible_p(n, d) != 0) ? V_EQ : V_LT;
449     }
450     return V_LE;
451   }
452 }
453 
PPL_SPECIALIZE_DIV(div_mpz,mpz_class,mpz_class,mpz_class)454 PPL_SPECIALIZE_DIV(div_mpz, mpz_class, mpz_class, mpz_class)
455 
456 template <typename To_Policy, typename From1_Policy, typename From2_Policy>
457 inline Result
458 idiv_mpz(mpz_class& to, const mpz_class& x, const mpz_class& y,
459         Rounding_Dir) {
460   if (CHECK_P(To_Policy::check_div_zero, ::sgn(y) == 0)) {
461     return assign_nan<To_Policy>(to, V_DIV_ZERO);
462   }
463   mpz_srcptr n = x.get_mpz_t();
464   mpz_srcptr d = y.get_mpz_t();
465   mpz_tdiv_q(to.get_mpz_t(), n, d);
466   return V_EQ;
467 }
468 
PPL_SPECIALIZE_IDIV(idiv_mpz,mpz_class,mpz_class,mpz_class)469 PPL_SPECIALIZE_IDIV(idiv_mpz, mpz_class, mpz_class, mpz_class)
470 
471 template <typename To_Policy, typename From1_Policy, typename From2_Policy>
472 inline Result
473 rem_mpz(mpz_class& to, const mpz_class& x, const mpz_class& y, Rounding_Dir) {
474   if (CHECK_P(To_Policy::check_div_zero, ::sgn(y) == 0)) {
475     return assign_nan<To_Policy>(to, V_MOD_ZERO);
476   }
477   to = x % y;
478   return V_EQ;
479 }
480 
PPL_SPECIALIZE_REM(rem_mpz,mpz_class,mpz_class,mpz_class)481 PPL_SPECIALIZE_REM(rem_mpz, mpz_class, mpz_class, mpz_class)
482 
483 template <typename To_Policy, typename From_Policy>
484 inline Result
485 add_2exp_mpz(mpz_class& to, const mpz_class& x, unsigned int exp,
486              Rounding_Dir) {
487   PPL_DIRTY_TEMP(mpz_class, v);
488   v = 1;
489   mpz_mul_2exp(v.get_mpz_t(), v.get_mpz_t(), exp);
490   to = x + v;
491   return V_EQ;
492 }
493 
PPL_SPECIALIZE_ADD_2EXP(add_2exp_mpz,mpz_class,mpz_class)494 PPL_SPECIALIZE_ADD_2EXP(add_2exp_mpz, mpz_class, mpz_class)
495 
496 template <typename To_Policy, typename From_Policy>
497 inline Result
498 sub_2exp_mpz(mpz_class& to, const mpz_class& x, unsigned int exp,
499              Rounding_Dir) {
500   PPL_DIRTY_TEMP(mpz_class, v);
501   v = 1;
502   mpz_mul_2exp(v.get_mpz_t(), v.get_mpz_t(), exp);
503   to = x - v;
504   return V_EQ;
505 }
506 
PPL_SPECIALIZE_SUB_2EXP(sub_2exp_mpz,mpz_class,mpz_class)507 PPL_SPECIALIZE_SUB_2EXP(sub_2exp_mpz, mpz_class, mpz_class)
508 
509 template <typename To_Policy, typename From_Policy>
510 inline Result
511 mul_2exp_mpz(mpz_class& to, const mpz_class& x, unsigned int exp,
512              Rounding_Dir) {
513   mpz_mul_2exp(to.get_mpz_t(), x.get_mpz_t(), exp);
514   return V_EQ;
515 }
516 
PPL_SPECIALIZE_MUL_2EXP(mul_2exp_mpz,mpz_class,mpz_class)517 PPL_SPECIALIZE_MUL_2EXP(mul_2exp_mpz, mpz_class, mpz_class)
518 
519 template <typename To_Policy, typename From_Policy>
520 inline Result
521 div_2exp_mpz(mpz_class& to, const mpz_class& x, unsigned int exp,
522              Rounding_Dir dir) {
523   const mpz_srcptr n = x.get_mpz_t();
524   if (round_not_requested(dir)) {
525     mpz_tdiv_q_2exp(to.get_mpz_t(), x.get_mpz_t(), exp);
526     return V_LGE;
527   }
528   if (round_down(dir)) {
529     mpz_fdiv_q_2exp(to.get_mpz_t(), n, exp);
530     if (round_strict_relation(dir)) {
531       return (mpz_divisible_2exp_p(n, exp) != 0) ? V_EQ : V_GT;
532     }
533     return V_GE;
534   }
535   else {
536     PPL_ASSERT(round_up(dir));
537     mpz_cdiv_q_2exp(to.get_mpz_t(), n, exp);
538     if (round_strict_relation(dir)) {
539       return (mpz_divisible_2exp_p(n, exp) != 0) ? V_EQ : V_LT;
540     }
541     return V_LE;
542   }
543 }
544 
PPL_SPECIALIZE_DIV_2EXP(div_2exp_mpz,mpz_class,mpz_class)545 PPL_SPECIALIZE_DIV_2EXP(div_2exp_mpz, mpz_class, mpz_class)
546 
547 template <typename To_Policy, typename From_Policy>
548 inline Result
549 smod_2exp_mpz(mpz_class& to, const mpz_class& x, unsigned int exp,
550               Rounding_Dir) {
551   if (mpz_tstbit(x.get_mpz_t(), exp - 1) != 0) {
552     mpz_cdiv_r_2exp(to.get_mpz_t(), x.get_mpz_t(), exp);
553   }
554   else {
555     mpz_fdiv_r_2exp(to.get_mpz_t(), x.get_mpz_t(), exp);
556   }
557   return V_EQ;
558 }
559 
PPL_SPECIALIZE_SMOD_2EXP(smod_2exp_mpz,mpz_class,mpz_class)560 PPL_SPECIALIZE_SMOD_2EXP(smod_2exp_mpz, mpz_class, mpz_class)
561 
562 template <typename To_Policy, typename From_Policy>
563 inline Result
564 umod_2exp_mpz(mpz_class& to, const mpz_class& x, unsigned int exp,
565               Rounding_Dir) {
566   mpz_fdiv_r_2exp(to.get_mpz_t(), x.get_mpz_t(), exp);
567   return V_EQ;
568 }
569 
PPL_SPECIALIZE_UMOD_2EXP(umod_2exp_mpz,mpz_class,mpz_class)570 PPL_SPECIALIZE_UMOD_2EXP(umod_2exp_mpz, mpz_class, mpz_class)
571 
572 template <typename To_Policy, typename From_Policy>
573 inline Result
574 abs_mpz(mpz_class& to, const mpz_class& from, Rounding_Dir) {
575   to = abs(from);
576   return V_EQ;
577 }
578 
PPL_SPECIALIZE_ABS(abs_mpz,mpz_class,mpz_class)579 PPL_SPECIALIZE_ABS(abs_mpz, mpz_class, mpz_class)
580 
581 template <typename To_Policy, typename From1_Policy, typename From2_Policy>
582 inline Result
583 add_mul_mpz(mpz_class& to, const mpz_class& x, const mpz_class& y,
584             Rounding_Dir) {
585   mpz_addmul(to.get_mpz_t(), x.get_mpz_t(), y.get_mpz_t());
586   return V_EQ;
587 }
588 
PPL_SPECIALIZE_ADD_MUL(add_mul_mpz,mpz_class,mpz_class,mpz_class)589 PPL_SPECIALIZE_ADD_MUL(add_mul_mpz, mpz_class, mpz_class, mpz_class)
590 
591 template <typename To_Policy, typename From1_Policy, typename From2_Policy>
592 inline Result
593 sub_mul_mpz(mpz_class& to, const mpz_class& x, const mpz_class& y,
594             Rounding_Dir) {
595   mpz_submul(to.get_mpz_t(), x.get_mpz_t(), y.get_mpz_t());
596   return V_EQ;
597 }
598 
PPL_SPECIALIZE_SUB_MUL(sub_mul_mpz,mpz_class,mpz_class,mpz_class)599 PPL_SPECIALIZE_SUB_MUL(sub_mul_mpz, mpz_class, mpz_class, mpz_class)
600 
601 template <typename To_Policy, typename From1_Policy, typename From2_Policy>
602 inline Result
603 gcd_mpz(mpz_class& to, const mpz_class& x, const mpz_class& y, Rounding_Dir) {
604   mpz_gcd(to.get_mpz_t(), x.get_mpz_t(), y.get_mpz_t());
605   return V_EQ;
606 }
607 
PPL_SPECIALIZE_GCD(gcd_mpz,mpz_class,mpz_class,mpz_class)608 PPL_SPECIALIZE_GCD(gcd_mpz, mpz_class, mpz_class, mpz_class)
609 
610 template <typename To_Policy, typename From1_Policy, typename From2_Policy>
611 inline Result
612 gcdext_mpz(mpz_class& to, mpz_class& s, mpz_class& t,
613            const mpz_class& x, const mpz_class& y,
614            Rounding_Dir) {
615   mpz_gcdext(to.get_mpz_t(), s.get_mpz_t(), t.get_mpz_t(),
616              x.get_mpz_t(), y.get_mpz_t());
617   return V_EQ;
618 }
619 
PPL_SPECIALIZE_GCDEXT(gcdext_mpz,mpz_class,mpz_class,mpz_class,mpz_class,mpz_class)620 PPL_SPECIALIZE_GCDEXT(gcdext_mpz, mpz_class, mpz_class, mpz_class, mpz_class, mpz_class)
621 
622 template <typename To_Policy, typename From1_Policy, typename From2_Policy>
623 inline Result
624 lcm_mpz(mpz_class& to, const mpz_class& x, const mpz_class& y, Rounding_Dir) {
625   mpz_lcm(to.get_mpz_t(), x.get_mpz_t(), y.get_mpz_t());
626   return V_EQ;
627 }
628 
PPL_SPECIALIZE_LCM(lcm_mpz,mpz_class,mpz_class,mpz_class)629 PPL_SPECIALIZE_LCM(lcm_mpz, mpz_class, mpz_class, mpz_class)
630 
631 template <typename To_Policy, typename From_Policy>
632 inline Result
633 sqrt_mpz(mpz_class& to, const mpz_class& from, Rounding_Dir dir) {
634   if (CHECK_P(To_Policy::check_sqrt_neg, from < 0)) {
635     return assign_nan<To_Policy>(to, V_SQRT_NEG);
636   }
637   if (round_not_requested(dir)) {
638     to = sqrt(from);
639     return V_GE;
640   }
641   PPL_DIRTY_TEMP(mpz_class, r);
642   mpz_sqrtrem(to.get_mpz_t(), r.get_mpz_t(), from.get_mpz_t());
643   if (r == 0) {
644     return V_EQ;
645   }
646   return round_gt_mpz<To_Policy>(to, dir);
647 }
648 
PPL_SPECIALIZE_SQRT(sqrt_mpz,mpz_class,mpz_class)649 PPL_SPECIALIZE_SQRT(sqrt_mpz, mpz_class, mpz_class)
650 
651 template <typename Policy, typename Type>
652 inline Result_Relation
653 sgn_mp(const Type& x) {
654   const int sign = ::sgn(x);
655   return (sign > 0) ? VR_GT : ((sign < 0) ? VR_LT : VR_EQ);
656 }
657 
PPL_SPECIALIZE_SGN(sgn_mp,mpz_class)658 PPL_SPECIALIZE_SGN(sgn_mp, mpz_class)
659 PPL_SPECIALIZE_SGN(sgn_mp, mpq_class)
660 
661 template <typename Policy1, typename Policy2, typename Type>
662 inline Result_Relation
663 cmp_mp(const Type& x, const Type& y) {
664   int i = ::cmp(x, y);
665   return (i > 0) ? VR_GT : ((i < 0) ? VR_LT : VR_EQ);
666 }
667 
PPL_SPECIALIZE_CMP(cmp_mp,mpz_class,mpz_class)668 PPL_SPECIALIZE_CMP(cmp_mp, mpz_class, mpz_class)
669 PPL_SPECIALIZE_CMP(cmp_mp, mpq_class, mpq_class)
670 
671 template <typename Policy>
672 inline Result
673 output_mpz(std::ostream& os, const mpz_class& from, const Numeric_Format&,
674            Rounding_Dir) {
675   os << from;
676   return V_EQ;
677 }
678 
679 PPL_SPECIALIZE_INPUT(input_generic, mpz_class)
680 PPL_SPECIALIZE_OUTPUT(output_mpz, mpz_class)
681 
682 } // namespace Checked
683 
684 } // namespace Parma_Polyhedra_Library
685 
686 #endif // !defined(PPL_checked_mpz_inlines_hh)
687