1 /* Specialized "checked" functions for GMP's mpq_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_mpq_inlines_hh
25 #define PPL_checked_mpq_inlines_hh 1
26
27 #include <sstream>
28 #include <climits>
29 #include <stdexcept>
30
31 namespace Parma_Polyhedra_Library {
32
33 namespace Checked {
34
35 template <typename Policy>
36 inline Result
classify_mpq(const mpq_class & v,bool nan,bool inf,bool sign)37 classify_mpq(const mpq_class& v, bool nan, bool inf, bool sign) {
38 if ((Policy::has_nan || Policy::has_infinity)
39 && ::sgn(v.get_den()) == 0) {
40 int s = ::sgn(v.get_num());
41 if (Policy::has_nan && (nan || sign) && s == 0) {
42 return V_NAN;
43 }
44 if (!inf && !sign) {
45 return V_LGE;
46 }
47 if (Policy::has_infinity) {
48 if (s < 0) {
49 return inf ? V_EQ_MINUS_INFINITY : V_LT;
50 }
51 if (s > 0) {
52 return inf ? V_EQ_PLUS_INFINITY : V_GT;
53 }
54 }
55 }
56 if (sign) {
57 return static_cast<Result>(sgn<Policy>(v));
58 }
59 return V_LGE;
60 }
61
PPL_SPECIALIZE_CLASSIFY(classify_mpq,mpq_class)62 PPL_SPECIALIZE_CLASSIFY(classify_mpq, mpq_class)
63
64 template <typename Policy>
65 inline bool
66 is_nan_mpq(const mpq_class& v) {
67 return Policy::has_nan
68 && ::sgn(v.get_den()) == 0
69 && ::sgn(v.get_num()) == 0;
70 }
71
PPL_SPECIALIZE_IS_NAN(is_nan_mpq,mpq_class)72 PPL_SPECIALIZE_IS_NAN(is_nan_mpq, mpq_class)
73
74 template <typename Policy>
75 inline bool
76 is_minf_mpq(const mpq_class& v) {
77 return Policy::has_infinity
78 && ::sgn(v.get_den()) == 0
79 && ::sgn(v.get_num()) < 0;
80 }
81
PPL_SPECIALIZE_IS_MINF(is_minf_mpq,mpq_class)82 PPL_SPECIALIZE_IS_MINF(is_minf_mpq, mpq_class)
83
84 template <typename Policy>
85 inline bool
86 is_pinf_mpq(const mpq_class& v) {
87 return Policy::has_infinity
88 && ::sgn(v.get_den()) == 0
89 && ::sgn(v.get_num()) > 0;
90 }
91
PPL_SPECIALIZE_IS_PINF(is_pinf_mpq,mpq_class)92 PPL_SPECIALIZE_IS_PINF(is_pinf_mpq, mpq_class)
93
94 template <typename Policy>
95 inline bool
96 is_int_mpq(const mpq_class& v) {
97 if ((Policy::has_infinity || Policy::has_nan)
98 && ::sgn(v.get_den()) == 0) {
99 return !(Policy::has_nan && ::sgn(v.get_num()) == 0);
100 }
101 else {
102 return v.get_den() == 1;
103 }
104 }
105
PPL_SPECIALIZE_IS_INT(is_int_mpq,mpq_class)106 PPL_SPECIALIZE_IS_INT(is_int_mpq, mpq_class)
107
108 template <typename Policy>
109 inline Result
110 assign_special_mpq(mpq_class& v, Result_Class c, Rounding_Dir) {
111 switch (c) {
112 case VC_NAN:
113 if (Policy::has_nan) {
114 v.get_num() = 0;
115 v.get_den() = 0;
116 return V_NAN | V_UNREPRESENTABLE;
117 }
118 return V_NAN;
119 case VC_MINUS_INFINITY:
120 if (Policy::has_infinity) {
121 v.get_num() = -1;
122 v.get_den() = 0;
123 return V_EQ_MINUS_INFINITY;
124 }
125 return V_EQ_MINUS_INFINITY | V_UNREPRESENTABLE;
126 case VC_PLUS_INFINITY:
127 if (Policy::has_infinity) {
128 v.get_num() = 1;
129 v.get_den() = 0;
130 return V_EQ_PLUS_INFINITY;
131 }
132 return V_EQ_PLUS_INFINITY | V_UNREPRESENTABLE;
133 default:
134 PPL_UNREACHABLE;
135 return V_NAN | V_UNREPRESENTABLE;
136 }
137 }
138
PPL_SPECIALIZE_ASSIGN_SPECIAL(assign_special_mpq,mpq_class)139 PPL_SPECIALIZE_ASSIGN_SPECIAL(assign_special_mpq, mpq_class)
140
141 PPL_SPECIALIZE_COPY(copy_generic, mpq_class)
142
143 template <typename To_Policy, typename From_Policy, typename From>
144 inline Result
145 construct_mpq_base(mpq_class& to, const From& from, Rounding_Dir) {
146 new(&to) mpq_class(from);
147 return V_EQ;
148 }
149
PPL_SPECIALIZE_CONSTRUCT(construct_mpq_base,mpq_class,mpz_class)150 PPL_SPECIALIZE_CONSTRUCT(construct_mpq_base, mpq_class, mpz_class)
151 PPL_SPECIALIZE_CONSTRUCT(construct_mpq_base, mpq_class, char)
152 PPL_SPECIALIZE_CONSTRUCT(construct_mpq_base, mpq_class, signed char)
153 PPL_SPECIALIZE_CONSTRUCT(construct_mpq_base, mpq_class, signed short)
154 PPL_SPECIALIZE_CONSTRUCT(construct_mpq_base, mpq_class, signed int)
155 PPL_SPECIALIZE_CONSTRUCT(construct_mpq_base, mpq_class, signed long)
156 PPL_SPECIALIZE_CONSTRUCT(construct_mpq_base, mpq_class, unsigned char)
157 PPL_SPECIALIZE_CONSTRUCT(construct_mpq_base, mpq_class, unsigned short)
158 PPL_SPECIALIZE_CONSTRUCT(construct_mpq_base, mpq_class, unsigned int)
159 PPL_SPECIALIZE_CONSTRUCT(construct_mpq_base, mpq_class, unsigned long)
160
161 template <typename To_Policy, typename From_Policy, typename From>
162 inline Result
163 construct_mpq_float(mpq_class& to, const From& from, Rounding_Dir dir) {
164 if (is_nan<From_Policy>(from)) {
165 return construct_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
166 }
167 else if (is_minf<From_Policy>(from)) {
168 return construct_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
169 }
170 else if (is_pinf<From_Policy>(from)) {
171 return construct_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
172 }
173 new(&to) mpq_class(from);
174 return V_EQ;
175 }
176
PPL_SPECIALIZE_CONSTRUCT(construct_mpq_float,mpq_class,float)177 PPL_SPECIALIZE_CONSTRUCT(construct_mpq_float, mpq_class, float)
178 PPL_SPECIALIZE_CONSTRUCT(construct_mpq_float, mpq_class, double)
179
180 PPL_SPECIALIZE_ASSIGN(assign_exact, mpq_class, mpq_class)
181 PPL_SPECIALIZE_ASSIGN(assign_exact, mpq_class, mpz_class)
182 PPL_SPECIALIZE_ASSIGN(assign_exact, mpq_class, char)
183 PPL_SPECIALIZE_ASSIGN(assign_exact, mpq_class, signed char)
184 PPL_SPECIALIZE_ASSIGN(assign_exact, mpq_class, signed short)
185 PPL_SPECIALIZE_ASSIGN(assign_exact, mpq_class, signed int)
186 PPL_SPECIALIZE_ASSIGN(assign_exact, mpq_class, signed long)
187 PPL_SPECIALIZE_ASSIGN(assign_exact, mpq_class, unsigned char)
188 PPL_SPECIALIZE_ASSIGN(assign_exact, mpq_class, unsigned short)
189 PPL_SPECIALIZE_ASSIGN(assign_exact, mpq_class, unsigned int)
190 PPL_SPECIALIZE_ASSIGN(assign_exact, mpq_class, unsigned long)
191
192 template <typename To_Policy, typename From_Policy, typename From>
193 inline Result
194 assign_mpq_float(mpq_class& to, const From& from, Rounding_Dir dir) {
195 if (is_nan<From_Policy>(from)) {
196 return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
197 }
198 else if (is_minf<From_Policy>(from)) {
199 return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
200 }
201 else if (is_pinf<From_Policy>(from)) {
202 return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
203 }
204 assign_mpq_numeric_float(to, from);
205 return V_EQ;
206 }
207
PPL_SPECIALIZE_ASSIGN(assign_mpq_float,mpq_class,float)208 PPL_SPECIALIZE_ASSIGN(assign_mpq_float, mpq_class, float)
209 PPL_SPECIALIZE_ASSIGN(assign_mpq_float, mpq_class, double)
210 PPL_SPECIALIZE_ASSIGN(assign_mpq_float, mpq_class, long double)
211
212 template <typename To_Policy, typename From_Policy, typename From>
213 inline Result
214 assign_mpq_signed_int(mpq_class& to, const From from, Rounding_Dir) {
215 if (sizeof(From) <= sizeof(signed long)) {
216 to = static_cast<signed long>(from);
217 }
218 else {
219 mpz_ptr m = to.get_num().get_mpz_t();
220 if (from >= 0) {
221 mpz_import(m, 1, 1, sizeof(From), 0, 0, &from);
222 }
223 else {
224 From n = -from;
225 mpz_import(m, 1, 1, sizeof(From), 0, 0, &n);
226 mpz_neg(m, m);
227 }
228 to.get_den() = 1;
229 }
230 return V_EQ;
231 }
232
PPL_SPECIALIZE_ASSIGN(assign_mpq_signed_int,mpq_class,signed long long)233 PPL_SPECIALIZE_ASSIGN(assign_mpq_signed_int, mpq_class, signed long long)
234
235 template <typename To_Policy, typename From_Policy, typename From>
236 inline Result
237 assign_mpq_unsigned_int(mpq_class& to, const From from, Rounding_Dir) {
238 if (sizeof(From) <= sizeof(unsigned long)) {
239 to = static_cast<unsigned long>(from);
240 }
241 else {
242 mpz_import(to.get_num().get_mpz_t(), 1, 1, sizeof(From), 0, 0, &from);
243 to.get_den() = 1;
244 }
245 return V_EQ;
246 }
247
PPL_SPECIALIZE_ASSIGN(assign_mpq_unsigned_int,mpq_class,unsigned long long)248 PPL_SPECIALIZE_ASSIGN(assign_mpq_unsigned_int, mpq_class, unsigned long long)
249
250 template <typename To_Policy, typename From_Policy>
251 inline Result
252 floor_mpq(mpq_class& to, const mpq_class& from, Rounding_Dir) {
253 mpz_fdiv_q(to.get_num().get_mpz_t(),
254 from.get_num().get_mpz_t(), from.get_den().get_mpz_t());
255 to.get_den() = 1;
256 return V_EQ;
257 }
258
PPL_SPECIALIZE_FLOOR(floor_mpq,mpq_class,mpq_class)259 PPL_SPECIALIZE_FLOOR(floor_mpq, mpq_class, mpq_class)
260
261 template <typename To_Policy, typename From_Policy>
262 inline Result
263 ceil_mpq(mpq_class& to, const mpq_class& from, Rounding_Dir) {
264 mpz_cdiv_q(to.get_num().get_mpz_t(),
265 from.get_num().get_mpz_t(), from.get_den().get_mpz_t());
266 to.get_den() = 1;
267 return V_EQ;
268 }
269
PPL_SPECIALIZE_CEIL(ceil_mpq,mpq_class,mpq_class)270 PPL_SPECIALIZE_CEIL(ceil_mpq, mpq_class, mpq_class)
271
272 template <typename To_Policy, typename From_Policy>
273 inline Result
274 trunc_mpq(mpq_class& to, const mpq_class& from, Rounding_Dir) {
275 mpz_tdiv_q(to.get_num().get_mpz_t(),
276 from.get_num().get_mpz_t(), from.get_den().get_mpz_t());
277 to.get_den() = 1;
278 return V_EQ;
279 }
280
PPL_SPECIALIZE_TRUNC(trunc_mpq,mpq_class,mpq_class)281 PPL_SPECIALIZE_TRUNC(trunc_mpq, mpq_class, mpq_class)
282
283 template <typename To_Policy, typename From_Policy>
284 inline Result
285 neg_mpq(mpq_class& to, const mpq_class& from, Rounding_Dir) {
286 mpq_neg(to.get_mpq_t(), from.get_mpq_t());
287 return V_EQ;
288 }
289
PPL_SPECIALIZE_NEG(neg_mpq,mpq_class,mpq_class)290 PPL_SPECIALIZE_NEG(neg_mpq, mpq_class, mpq_class)
291
292 template <typename To_Policy, typename From1_Policy, typename From2_Policy>
293 inline Result
294 add_mpq(mpq_class& to, const mpq_class& x, const mpq_class& y, Rounding_Dir) {
295 to = x + y;
296 return V_EQ;
297 }
298
PPL_SPECIALIZE_ADD(add_mpq,mpq_class,mpq_class,mpq_class)299 PPL_SPECIALIZE_ADD(add_mpq, mpq_class, mpq_class, mpq_class)
300
301 template <typename To_Policy, typename From1_Policy, typename From2_Policy>
302 inline Result
303 sub_mpq(mpq_class& to, const mpq_class& x, const mpq_class& y, Rounding_Dir) {
304 to = x - y;
305 return V_EQ;
306 }
307
PPL_SPECIALIZE_SUB(sub_mpq,mpq_class,mpq_class,mpq_class)308 PPL_SPECIALIZE_SUB(sub_mpq, mpq_class, mpq_class, mpq_class)
309
310 template <typename To_Policy, typename From1_Policy, typename From2_Policy>
311 inline Result
312 mul_mpq(mpq_class& to, const mpq_class& x, const mpq_class& y, Rounding_Dir) {
313 to = x * y;
314 return V_EQ;
315 }
316
PPL_SPECIALIZE_MUL(mul_mpq,mpq_class,mpq_class,mpq_class)317 PPL_SPECIALIZE_MUL(mul_mpq, mpq_class, mpq_class, mpq_class)
318
319 template <typename To_Policy, typename From1_Policy, typename From2_Policy>
320 inline Result
321 div_mpq(mpq_class& to, const mpq_class& x, const mpq_class& y, Rounding_Dir) {
322 if (CHECK_P(To_Policy::check_div_zero, sgn(y) == 0)) {
323 return assign_nan<To_Policy>(to, V_DIV_ZERO);
324 }
325 to = x / y;
326 return V_EQ;
327 }
328
PPL_SPECIALIZE_DIV(div_mpq,mpq_class,mpq_class,mpq_class)329 PPL_SPECIALIZE_DIV(div_mpq, mpq_class, mpq_class, mpq_class)
330
331 template <typename To_Policy, typename From1_Policy, typename From2_Policy>
332 inline Result
333 idiv_mpq(mpq_class& to, const mpq_class& x, const mpq_class& y, Rounding_Dir dir) {
334 if (CHECK_P(To_Policy::check_div_zero, sgn(y) == 0)) {
335 return assign_nan<To_Policy>(to, V_DIV_ZERO);
336 }
337 to = x / y;
338 return trunc<To_Policy, To_Policy>(to, to, dir);
339 }
340
PPL_SPECIALIZE_IDIV(idiv_mpq,mpq_class,mpq_class,mpq_class)341 PPL_SPECIALIZE_IDIV(idiv_mpq, mpq_class, mpq_class, mpq_class)
342
343 template <typename To_Policy, typename From1_Policy, typename From2_Policy>
344 inline Result
345 rem_mpq(mpq_class& to, const mpq_class& x, const mpq_class& y, Rounding_Dir) {
346 if (CHECK_P(To_Policy::check_div_zero, sgn(y) == 0)) {
347 return assign_nan<To_Policy>(to, V_MOD_ZERO);
348 }
349 PPL_DIRTY_TEMP(mpq_class, tmp);
350 tmp = x / y;
351 tmp.get_num() %= tmp.get_den();
352 to = tmp * y;
353 return V_EQ;
354 }
355
PPL_SPECIALIZE_REM(rem_mpq,mpq_class,mpq_class,mpq_class)356 PPL_SPECIALIZE_REM(rem_mpq, mpq_class, mpq_class, mpq_class)
357
358 template <typename To_Policy, typename From_Policy>
359 inline Result
360 add_2exp_mpq(mpq_class& to, const mpq_class& x, unsigned int exp,
361 Rounding_Dir) {
362 PPL_DIRTY_TEMP(mpz_class, v);
363 v = 1;
364 mpz_mul_2exp(v.get_mpz_t(), v.get_mpz_t(), exp);
365 to = x + v;
366 return V_EQ;
367 }
368
PPL_SPECIALIZE_ADD_2EXP(add_2exp_mpq,mpq_class,mpq_class)369 PPL_SPECIALIZE_ADD_2EXP(add_2exp_mpq, mpq_class, mpq_class)
370
371 template <typename To_Policy, typename From_Policy>
372 inline Result
373 sub_2exp_mpq(mpq_class& to, const mpq_class& x, unsigned int exp,
374 Rounding_Dir) {
375 PPL_DIRTY_TEMP(mpz_class, v);
376 v = 1;
377 mpz_mul_2exp(v.get_mpz_t(), v.get_mpz_t(), exp);
378 to = x - v;
379 return V_EQ;
380 }
381
PPL_SPECIALIZE_SUB_2EXP(sub_2exp_mpq,mpq_class,mpq_class)382 PPL_SPECIALIZE_SUB_2EXP(sub_2exp_mpq, mpq_class, mpq_class)
383
384 template <typename To_Policy, typename From_Policy>
385 inline Result
386 mul_2exp_mpq(mpq_class& to, const mpq_class& x, unsigned int exp,
387 Rounding_Dir) {
388 mpz_mul_2exp(to.get_num().get_mpz_t(), x.get_num().get_mpz_t(), exp);
389 to.get_den() = x.get_den();
390 to.canonicalize();
391 return V_EQ;
392 }
393
PPL_SPECIALIZE_MUL_2EXP(mul_2exp_mpq,mpq_class,mpq_class)394 PPL_SPECIALIZE_MUL_2EXP(mul_2exp_mpq, mpq_class, mpq_class)
395
396 template <typename To_Policy, typename From_Policy>
397 inline Result
398 div_2exp_mpq(mpq_class& to, const mpq_class& x, unsigned int exp,
399 Rounding_Dir) {
400 to.get_num() = x.get_num();
401 mpz_mul_2exp(to.get_den().get_mpz_t(), x.get_den().get_mpz_t(), exp);
402 to.canonicalize();
403 return V_EQ;
404 }
405
PPL_SPECIALIZE_DIV_2EXP(div_2exp_mpq,mpq_class,mpq_class)406 PPL_SPECIALIZE_DIV_2EXP(div_2exp_mpq, mpq_class, mpq_class)
407
408 template <typename To_Policy, typename From_Policy>
409 inline Result
410 smod_2exp_mpq(mpq_class& to, const mpq_class& x, unsigned int exp,
411 Rounding_Dir) {
412 mpz_mul_2exp(to.get_den().get_mpz_t(), x.get_den().get_mpz_t(), exp);
413 mpz_fdiv_r(to.get_num().get_mpz_t(), x.get_num().get_mpz_t(), to.get_den().get_mpz_t());
414 mpz_fdiv_q_2exp(to.get_den().get_mpz_t(), to.get_den().get_mpz_t(), 1);
415 bool neg = to.get_num() >= to.get_den();
416 mpz_mul_2exp(to.get_den().get_mpz_t(), to.get_den().get_mpz_t(), 1);
417 if (neg) {
418 to.get_num() -= to.get_den();
419 }
420 mpz_mul_2exp(to.get_num().get_mpz_t(), to.get_num().get_mpz_t(), exp);
421 to.canonicalize();
422 return V_EQ;
423 }
424
PPL_SPECIALIZE_SMOD_2EXP(smod_2exp_mpq,mpq_class,mpq_class)425 PPL_SPECIALIZE_SMOD_2EXP(smod_2exp_mpq, mpq_class, mpq_class)
426
427 template <typename To_Policy, typename From_Policy>
428 inline Result
429 umod_2exp_mpq(mpq_class& to, const mpq_class& x, unsigned int exp,
430 Rounding_Dir) {
431 mpz_mul_2exp(to.get_den().get_mpz_t(), x.get_den().get_mpz_t(), exp);
432 mpz_fdiv_r(to.get_num().get_mpz_t(), x.get_num().get_mpz_t(), to.get_den().get_mpz_t());
433 mpz_mul_2exp(to.get_num().get_mpz_t(), to.get_num().get_mpz_t(), exp);
434 to.canonicalize();
435 return V_EQ;
436 }
437
PPL_SPECIALIZE_UMOD_2EXP(umod_2exp_mpq,mpq_class,mpq_class)438 PPL_SPECIALIZE_UMOD_2EXP(umod_2exp_mpq, mpq_class, mpq_class)
439
440 template <typename To_Policy, typename From_Policy>
441 inline Result
442 abs_mpq(mpq_class& to, const mpq_class& from, Rounding_Dir) {
443 to = abs(from);
444 return V_EQ;
445 }
446
PPL_SPECIALIZE_ABS(abs_mpq,mpq_class,mpq_class)447 PPL_SPECIALIZE_ABS(abs_mpq, mpq_class, mpq_class)
448
449 template <typename To_Policy, typename From1_Policy, typename From2_Policy>
450 inline Result
451 add_mul_mpq(mpq_class& to, const mpq_class& x, const mpq_class& y,
452 Rounding_Dir) {
453 to += x * y;
454 return V_EQ;
455 }
456
PPL_SPECIALIZE_ADD_MUL(add_mul_mpq,mpq_class,mpq_class,mpq_class)457 PPL_SPECIALIZE_ADD_MUL(add_mul_mpq, mpq_class, mpq_class, mpq_class)
458
459 template <typename To_Policy, typename From1_Policy, typename From2_Policy>
460 inline Result
461 sub_mul_mpq(mpq_class& to, const mpq_class& x, const mpq_class& y,
462 Rounding_Dir) {
463 to -= x * y;
464 return V_EQ;
465 }
466
467 PPL_SPECIALIZE_SUB_MUL(sub_mul_mpq, mpq_class, mpq_class, mpq_class)
468
469 extern unsigned irrational_precision;
470
471 template <typename To_Policy, typename From_Policy>
472 inline Result
sqrt_mpq(mpq_class & to,const mpq_class & from,Rounding_Dir dir)473 sqrt_mpq(mpq_class& to, const mpq_class& from, Rounding_Dir dir) {
474 if (CHECK_P(To_Policy::check_sqrt_neg, from < 0)) {
475 return assign_nan<To_Policy>(to, V_SQRT_NEG);
476 }
477 if (from == 0) {
478 to = 0;
479 return V_EQ;
480 }
481 bool gt1 = from.get_num() > from.get_den();
482 const mpz_class& from_a = gt1 ? from.get_num() : from.get_den();
483 const mpz_class& from_b = gt1 ? from.get_den() : from.get_num();
484 mpz_class& to_a = gt1 ? to.get_num() : to.get_den();
485 mpz_class& to_b = gt1 ? to.get_den() : to.get_num();
486 Rounding_Dir rdir = gt1 ? dir : inverse(dir);
487 mul_2exp<To_Policy, From_Policy>(to_a, from_a,
488 2*irrational_precision, ROUND_IGNORE);
489 Result r_div
490 = div<To_Policy, To_Policy, To_Policy>(to_a, to_a, from_b, rdir);
491 Result r_sqrt = sqrt<To_Policy, To_Policy>(to_a, to_a, rdir);
492 to_b = 1;
493 mul_2exp<To_Policy, To_Policy>(to_b, to_b,
494 irrational_precision, ROUND_IGNORE);
495 to.canonicalize();
496 return (r_div != V_EQ) ? r_div : r_sqrt;
497 }
498
PPL_SPECIALIZE_SQRT(sqrt_mpq,mpq_class,mpq_class)499 PPL_SPECIALIZE_SQRT(sqrt_mpq, mpq_class, mpq_class)
500
501 template <typename Policy>
502 inline Result
503 input_mpq(mpq_class& to, std::istream& is, Rounding_Dir dir) {
504 Result r = input_mpq(to, is);
505 Result_Class c = result_class(r);
506 switch (c) {
507 case VC_MINUS_INFINITY:
508 case VC_PLUS_INFINITY:
509 return assign_special<Policy>(to, c, dir);
510 case VC_NAN:
511 return assign_nan<Policy>(to, r);
512 default:
513 return r;
514 }
515 }
516
PPL_SPECIALIZE_INPUT(input_mpq,mpq_class)517 PPL_SPECIALIZE_INPUT(input_mpq, mpq_class)
518
519 template <typename Policy>
520 inline Result
521 output_mpq(std::ostream& os,
522 const mpq_class& from,
523 const Numeric_Format&,
524 Rounding_Dir) {
525 os << from;
526 return V_EQ;
527 }
528
529 PPL_SPECIALIZE_OUTPUT(output_mpq, mpq_class)
530
531 } // namespace Checked
532
533 //! Returns the precision parameter used for irrational calculations.
534 inline unsigned
irrational_precision()535 irrational_precision() {
536 return Checked::irrational_precision;
537 }
538
539 //! Sets the precision parameter used for irrational calculations.
540 /*! The lesser between numerator and denominator is limited to 2**\p p.
541
542 If \p p is less than or equal to <CODE>INT_MAX</CODE>, sets the
543 precision parameter used for irrational calculations to \p p.
544
545 \exception std::invalid_argument
546 Thrown if \p p is greater than <CODE>INT_MAX</CODE>.
547 */
548 inline void
set_irrational_precision(const unsigned p)549 set_irrational_precision(const unsigned p) {
550 if (p <= INT_MAX) {
551 Checked::irrational_precision = p;
552 }
553 else {
554 throw std::invalid_argument("PPL::set_irrational_precision(p)"
555 " with p > INT_MAX");
556 }
557 }
558
559 } // namespace Parma_Polyhedra_Library
560
561 #endif // !defined(PPL_checked_mpq_inlines_hh)
562