1 /* Checked extended arithmetic functions.
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_ext_defs_hh
25 #define PPL_checked_ext_defs_hh 1
26 
27 namespace Parma_Polyhedra_Library {
28 
29 template <typename T> struct FPU_Related : public False {};
30 template <> struct FPU_Related<float> : public True {};
31 template <> struct FPU_Related<double> : public True {};
32 template <> struct FPU_Related<long double> : public True {};
33 
34 namespace Checked {
35 
36 template <typename T>
37 inline bool
handle_ext_natively(const T &)38 handle_ext_natively(const T&) {
39   return FPU_Related<T>::value;
40 }
41 
42 template <typename Policy, typename Type>
43 inline bool
ext_to_handle(const Type & x)44 ext_to_handle(const Type& x) {
45   return !handle_ext_natively(x)
46     && (Policy::has_infinity || Policy::has_nan);
47 }
48 
49 template <typename Policy, typename Type>
50 inline Result_Relation
sgn_ext(const Type & x)51 sgn_ext(const Type& x) {
52   if (!ext_to_handle<Policy>(x)) {
53     goto native;
54   }
55   if (is_nan<Policy>(x)) {
56     return VR_EMPTY;
57   }
58   else if (is_minf<Policy>(x)) {
59     return VR_LT;
60   }
61   else if (is_pinf<Policy>(x)) {
62     return VR_GT;
63   }
64   else {
65   native:
66     return sgn<Policy>(x);
67   }
68 }
69 
70 template <typename To_Policy, typename From_Policy,
71           typename To, typename From>
72 inline Result
construct_ext(To & to,const From & x,Rounding_Dir dir)73 construct_ext(To& to, const From& x, Rounding_Dir dir) {
74   if (!ext_to_handle<From_Policy>(x)) {
75     goto native;
76   }
77   if (is_nan<From_Policy>(x)) {
78     return construct_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
79   }
80   else if (is_minf<From_Policy>(x)) {
81     return construct_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
82   }
83   else if (is_pinf<From_Policy>(x)) {
84     return construct_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
85   }
86   else {
87   native:
88     return construct<To_Policy, From_Policy>(to, x, dir);
89   }
90 }
91 
92 template <typename To_Policy, typename From_Policy,
93           typename To, typename From>
94 inline Result
assign_ext(To & to,const From & x,Rounding_Dir dir)95 assign_ext(To& to, const From& x, Rounding_Dir dir) {
96   if (!ext_to_handle<From_Policy>(x)) {
97     goto native;
98   }
99   if (is_nan<From_Policy>(x)) {
100     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
101   }
102   else if (is_minf<From_Policy>(x)) {
103     return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
104   }
105   else if (is_pinf<From_Policy>(x)) {
106     return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
107   }
108   else {
109   native:
110     return assign<To_Policy, From_Policy>(to, x, dir);
111   }
112 }
113 
114 template <typename To_Policy, typename From_Policy,
115           typename To, typename From>
116 inline Result
neg_ext(To & to,const From & x,Rounding_Dir dir)117 neg_ext(To& to, const From& x, Rounding_Dir dir) {
118   if (!ext_to_handle<From_Policy>(x)) {
119     goto native;
120   }
121   if (is_nan<From_Policy>(x)) {
122     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
123   }
124   else if (is_minf<From_Policy>(x)) {
125     return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
126   }
127   else if (is_pinf<From_Policy>(x)) {
128     return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
129   }
130   else {
131   native:
132     return neg<To_Policy, From_Policy>(to, x, dir);
133   }
134 }
135 
136 template <typename To_Policy, typename From_Policy,
137           typename To, typename From>
138 inline Result
floor_ext(To & to,const From & x,Rounding_Dir dir)139 floor_ext(To& to, const From& x, Rounding_Dir dir) {
140   if (!ext_to_handle<From_Policy>(x)) {
141     goto native;
142   }
143   if (is_nan<From_Policy>(x)) {
144     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
145   }
146   else if (is_minf<From_Policy>(x)) {
147     return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
148   }
149   else if (is_pinf<From_Policy>(x)) {
150     return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
151   }
152   else {
153   native:
154     return floor<To_Policy, From_Policy>(to, x, dir);
155   }
156 }
157 
158 template <typename To_Policy, typename From_Policy,
159           typename To, typename From>
160 inline Result
ceil_ext(To & to,const From & x,Rounding_Dir dir)161 ceil_ext(To& to, const From& x, Rounding_Dir dir) {
162   if (!ext_to_handle<From_Policy>(x)) {
163     goto native;
164   }
165   if (is_nan<From_Policy>(x)) {
166     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
167   }
168   else if (is_minf<From_Policy>(x)) {
169     return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
170   }
171   else if (is_pinf<From_Policy>(x)) {
172     return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
173   }
174   else {
175   native:
176     return ceil<To_Policy, From_Policy>(to, x, dir);
177   }
178 }
179 
180 template <typename To_Policy, typename From_Policy,
181           typename To, typename From>
182 inline Result
trunc_ext(To & to,const From & x,Rounding_Dir dir)183 trunc_ext(To& to, const From& x, Rounding_Dir dir) {
184   if (!ext_to_handle<From_Policy>(x)) {
185     goto native;
186   }
187   if (is_nan<From_Policy>(x)) {
188     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
189   }
190   else if (is_minf<From_Policy>(x)) {
191     return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
192   }
193   else if (is_pinf<From_Policy>(x)) {
194     return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
195   }
196   else {
197   native:
198     return trunc<To_Policy, From_Policy>(to, x, dir);
199   }
200 }
201 
202 template <typename To_Policy, typename From_Policy,
203           typename To, typename From>
204 inline Result
abs_ext(To & to,const From & x,Rounding_Dir dir)205 abs_ext(To& to, const From& x, Rounding_Dir dir) {
206   if (!ext_to_handle<From_Policy>(x)) {
207     goto native;
208   }
209   if (is_nan<From_Policy>(x)) {
210     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
211   }
212   else if (is_minf<From_Policy>(x) || is_pinf<From_Policy>(x)) {
213     return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
214   }
215   else {
216   native:
217     return abs<To_Policy, From_Policy>(to, x, dir);
218   }
219 }
220 
221 template <typename To_Policy, typename From1_Policy, typename From2_Policy,
222           typename To, typename From1, typename From2>
223 inline Result
add_ext(To & to,const From1 & x,const From2 & y,Rounding_Dir dir)224 add_ext(To& to, const From1& x, const From2& y, Rounding_Dir dir) {
225   if (!ext_to_handle<From1_Policy>(x) && !ext_to_handle<From2_Policy>(y)) {
226     goto native;
227   }
228   if (is_nan<From1_Policy>(x) || is_nan<From2_Policy>(y)) {
229     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
230   }
231   else if (is_minf<From1_Policy>(x)) {
232     if (CHECK_P(To_Policy::check_inf_add_inf, is_pinf<From2_Policy>(y))) {
233       goto inf_add_inf;
234     }
235     else {
236       goto minf;
237     }
238   }
239   else if (is_pinf<From1_Policy>(x)) {
240     if (CHECK_P(To_Policy::check_inf_add_inf, is_minf<From2_Policy>(y))) {
241     inf_add_inf:
242       return assign_nan<To_Policy>(to, V_INF_ADD_INF);
243     }
244     else {
245       goto pinf;
246     }
247   }
248   else {
249     if (is_minf<From2_Policy>(y)) {
250     minf:
251       return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
252     }
253     else if (is_pinf<From2_Policy>(y)) {
254     pinf:
255       return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
256     }
257     else {
258     native:
259       return add<To_Policy, From1_Policy, From2_Policy>(to, x, y, dir);
260     }
261   }
262 }
263 
264 template <typename To_Policy, typename From1_Policy, typename From2_Policy,
265           typename To, typename From1, typename From2>
266 inline Result
sub_ext(To & to,const From1 & x,const From2 & y,Rounding_Dir dir)267 sub_ext(To& to, const From1& x, const From2& y, Rounding_Dir dir) {
268   if (!ext_to_handle<From1_Policy>(x) && !ext_to_handle<From2_Policy>(y)) {
269     goto native;
270   }
271   if (is_nan<From1_Policy>(x) || is_nan<From2_Policy>(y)) {
272     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
273   }
274   else if (is_minf<From1_Policy>(x)) {
275     if (CHECK_P(To_Policy::check_inf_sub_inf, is_minf<From2_Policy>(y))) {
276       goto inf_sub_inf;
277     }
278     else {
279       goto minf;
280     }
281   }
282   else if (is_pinf<From1_Policy>(x)) {
283     if (CHECK_P(To_Policy::check_inf_sub_inf, is_pinf<From2_Policy>(y))) {
284     inf_sub_inf:
285       return assign_nan<To_Policy>(to, V_INF_SUB_INF);
286     }
287     else {
288       goto pinf;
289     }
290   }
291   else {
292     if (is_pinf<From2_Policy>(y)) {
293     minf:
294       return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
295     }
296     else if (is_minf<From2_Policy>(y)) {
297     pinf:
298       return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
299     }
300     else {
301     native:
302       return sub<To_Policy, From1_Policy, From2_Policy>(to, x, y, dir);
303     }
304   }
305 }
306 
307 template <typename To_Policy, typename From1_Policy, typename From2_Policy,
308           typename To, typename From1, typename From2>
309 inline Result
mul_ext(To & to,const From1 & x,const From2 & y,Rounding_Dir dir)310 mul_ext(To& to, const From1& x, const From2& y, Rounding_Dir dir) {
311   if (!ext_to_handle<From1_Policy>(x) && !ext_to_handle<From2_Policy>(y)) {
312     goto native;
313   }
314   if (is_nan<From1_Policy>(x) || is_nan<From2_Policy>(y)) {
315     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
316   }
317   if (is_minf<From1_Policy>(x)) {
318     switch (sgn_ext<From2_Policy>(y)) {
319     case VR_LT:
320       goto pinf;
321     case VR_GT:
322       goto minf;
323     default:
324       goto inf_mul_zero;
325     }
326   }
327   else if (is_pinf<From1_Policy>(x)) {
328     switch (sgn_ext<From2_Policy>(y)) {
329     case VR_LT:
330       goto minf;
331     case VR_GT:
332       goto pinf;
333     default:
334       goto inf_mul_zero;
335     }
336   }
337   else {
338     if (is_minf<From2_Policy>(y)) {
339       switch (sgn<From1_Policy>(x)) {
340       case VR_LT:
341         goto pinf;
342       case VR_GT:
343         goto minf;
344       default:
345         goto inf_mul_zero;
346       }
347     }
348     else if (is_pinf<From2_Policy>(y)) {
349       switch (sgn<From1_Policy>(x)) {
350       case VR_LT:
351       minf:
352         return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
353       case VR_GT:
354       pinf:
355         return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
356       default:
357       inf_mul_zero:
358         PPL_ASSERT(To_Policy::check_inf_mul_zero);
359         return assign_nan<To_Policy>(to, V_INF_MUL_ZERO);
360       }
361     }
362     else {
363     native:
364       return mul<To_Policy, From1_Policy, From2_Policy>(to, x, y, dir);
365     }
366   }
367 }
368 
369 
370 template <typename To_Policy, typename From1_Policy, typename From2_Policy,
371           typename To, typename From1, typename From2>
372 inline Result
add_mul_ext(To & to,const From1 & x,const From2 & y,Rounding_Dir dir)373 add_mul_ext(To& to, const From1& x, const From2& y, Rounding_Dir dir) {
374   if (!ext_to_handle<To_Policy>(to)
375       && !ext_to_handle<From1_Policy>(x) && !ext_to_handle<From2_Policy>(y)) {
376     goto native;
377   }
378   if (is_nan<To_Policy>(to)
379       || is_nan<From1_Policy>(x) || is_nan<From2_Policy>(y)) {
380     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
381   }
382   if (is_minf<From1_Policy>(x)) {
383     switch (sgn_ext<From2_Policy>(y)) {
384     case VR_LT:
385       goto a_pinf;
386     case VR_GT:
387       goto a_minf;
388     default:
389       goto inf_mul_zero;
390     }
391   }
392   else if (is_pinf<From1_Policy>(x)) {
393     switch (sgn_ext<From2_Policy>(y)) {
394     case VR_LT:
395       goto a_minf;
396     case VR_GT:
397       goto a_pinf;
398     default:
399       goto inf_mul_zero;
400     }
401   }
402   else {
403     if (is_minf<From2_Policy>(y)) {
404       switch (sgn<From1_Policy>(x)) {
405       case VR_LT:
406         goto a_pinf;
407       case VR_GT:
408         goto a_minf;
409       default:
410         goto inf_mul_zero;
411       }
412     }
413     else if (is_pinf<From2_Policy>(y)) {
414       switch (sgn<From1_Policy>(x)) {
415       case VR_LT:
416       a_minf:
417         if (CHECK_P(To_Policy::check_inf_add_inf, is_pinf<To_Policy>(to))) {
418           goto inf_add_inf;
419         }
420         else {
421           goto minf;
422         }
423       case VR_GT:
424       a_pinf:
425         if (CHECK_P(To_Policy::check_inf_add_inf, is_minf<To_Policy>(to))) {
426         inf_add_inf:
427           return assign_nan<To_Policy>(to, V_INF_ADD_INF);
428         }
429         else {
430           goto pinf;
431         }
432       default:
433       inf_mul_zero:
434         PPL_ASSERT(To_Policy::check_inf_mul_zero);
435         return assign_nan<To_Policy>(to, V_INF_MUL_ZERO);
436       }
437     }
438     else {
439       if (is_minf<To_Policy>(to)) {
440       minf:
441         return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
442       }
443       if (is_pinf<To_Policy>(to)) {
444       pinf:
445         return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
446       }
447     native:
448       return add_mul<To_Policy, From1_Policy, From2_Policy>(to, x, y, dir);
449     }
450   }
451 }
452 
453 template <typename To_Policy, typename From1_Policy, typename From2_Policy,
454           typename To, typename From1, typename From2>
455 inline Result
sub_mul_ext(To & to,const From1 & x,const From2 & y,Rounding_Dir dir)456 sub_mul_ext(To& to, const From1& x, const From2& y, Rounding_Dir dir) {
457   if (!ext_to_handle<To_Policy>(to)
458       && !ext_to_handle<From1_Policy>(x) && !ext_to_handle<From2_Policy>(y)) {
459     goto native;
460   }
461   if (is_nan<To_Policy>(to)
462       || is_nan<From1_Policy>(x) || is_nan<From2_Policy>(y)) {
463     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
464   }
465   if (is_minf<From1_Policy>(x)) {
466     switch (sgn_ext<From2_Policy>(y)) {
467     case VR_LT:
468       goto a_pinf;
469     case VR_GT:
470       goto a_minf;
471     default:
472       goto inf_mul_zero;
473     }
474   }
475   else if (is_pinf<From1_Policy>(x)) {
476     switch (sgn_ext<From2_Policy>(y)) {
477     case VR_LT:
478       goto a_minf;
479     case VR_GT:
480       goto a_pinf;
481     default:
482       goto inf_mul_zero;
483     }
484   }
485   else {
486     if (is_minf<From2_Policy>(y)) {
487       switch (sgn<From1_Policy>(x)) {
488       case VR_LT:
489         goto a_pinf;
490       case VR_GT:
491         goto a_minf;
492       default:
493         goto inf_mul_zero;
494       }
495     }
496     else if (is_pinf<From2_Policy>(y)) {
497       switch (sgn<From1_Policy>(x)) {
498       case VR_LT:
499       a_minf:
500         if (CHECK_P(To_Policy::check_inf_sub_inf, is_minf<To_Policy>(to))) {
501           goto inf_sub_inf;
502         }
503         else {
504           goto pinf;
505         }
506       case VR_GT:
507       a_pinf:
508         if (CHECK_P(To_Policy::check_inf_sub_inf, is_pinf<To_Policy>(to))) {
509         inf_sub_inf:
510           return assign_nan<To_Policy>(to, V_INF_SUB_INF);
511         }
512         else {
513           goto minf;
514         }
515       default:
516       inf_mul_zero:
517         PPL_ASSERT(To_Policy::check_inf_mul_zero);
518         return assign_nan<To_Policy>(to, V_INF_MUL_ZERO);
519       }
520     }
521     else {
522       if (is_minf<To_Policy>(to)) {
523       minf:
524         return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
525       }
526       if (is_pinf<To_Policy>(to)) {
527       pinf:
528         return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
529       }
530     native:
531       return sub_mul<To_Policy, From1_Policy, From2_Policy>(to, x, y, dir);
532     }
533   }
534 }
535 
536 template <typename To_Policy, typename From1_Policy, typename From2_Policy,
537           typename To, typename From1, typename From2>
538 inline Result
div_ext(To & to,const From1 & x,const From2 & y,Rounding_Dir dir)539 div_ext(To& to, const From1& x, const From2& y, Rounding_Dir dir) {
540   if (!ext_to_handle<From1_Policy>(x) && !ext_to_handle<From2_Policy>(y)) {
541     goto native;
542   }
543   if (is_nan<From1_Policy>(x) || is_nan<From2_Policy>(y)) {
544     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
545   }
546   if (is_minf<From1_Policy>(x)) {
547     if (CHECK_P(To_Policy::check_inf_div_inf, is_minf<From2_Policy>(y)
548                 || is_pinf<From2_Policy>(y))) {
549       goto inf_div_inf;
550     }
551     else {
552       switch (sgn<From2_Policy>(y)) {
553       case VR_LT:
554         goto pinf;
555       case VR_GT:
556         goto minf;
557       default:
558         goto div_zero;
559       }
560     }
561   }
562   else if (is_pinf<From1_Policy>(x)) {
563     if (CHECK_P(To_Policy::check_inf_div_inf, is_minf<From2_Policy>(y)
564                 || is_pinf<From2_Policy>(y))) {
565     inf_div_inf:
566       return assign_nan<To_Policy>(to, V_INF_DIV_INF);
567     }
568     else {
569       switch (sgn<From2_Policy>(y)) {
570       case VR_LT:
571       minf:
572         return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
573       case VR_GT:
574       pinf:
575         return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
576       default:
577       div_zero:
578         PPL_ASSERT(To_Policy::check_div_zero);
579         return assign_nan<To_Policy>(to, V_DIV_ZERO);
580       }
581     }
582   }
583   else {
584     if (is_minf<From2_Policy>(y) || is_pinf<From2_Policy>(y)) {
585       to = 0;
586       return V_EQ;
587     }
588     else {
589     native:
590       return div<To_Policy, From1_Policy, From2_Policy>(to, x, y, dir);
591     }
592   }
593 }
594 
595 
596 template <typename To_Policy, typename From1_Policy, typename From2_Policy,
597           typename To, typename From1, typename From2>
598 inline Result
idiv_ext(To & to,const From1 & x,const From2 & y,Rounding_Dir dir)599 idiv_ext(To& to, const From1& x, const From2& y, Rounding_Dir dir) {
600   if (!ext_to_handle<From1_Policy>(x) && !ext_to_handle<From2_Policy>(y)) {
601     goto native;
602   }
603   if (is_nan<From1_Policy>(x) || is_nan<From2_Policy>(y)) {
604     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
605   }
606   if (is_minf<From1_Policy>(x)) {
607     if (CHECK_P(To_Policy::check_inf_div_inf, is_minf<From2_Policy>(y)
608                 || is_pinf<From2_Policy>(y))) {
609       goto inf_div_inf;
610     }
611     else {
612       switch (sgn<From2_Policy>(y)) {
613       case VR_LT:
614         goto pinf;
615       case VR_GT:
616         goto minf;
617       default:
618         goto div_zero;
619       }
620     }
621   }
622   else if (is_pinf<From1_Policy>(x)) {
623     if (CHECK_P(To_Policy::check_inf_div_inf, is_minf<From2_Policy>(y)
624                 || is_pinf<From2_Policy>(y))) {
625     inf_div_inf:
626       return assign_nan<To_Policy>(to, V_INF_DIV_INF);
627     }
628     else {
629       switch (sgn<From2_Policy>(y)) {
630       case VR_LT:
631       minf:
632         return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
633       case VR_GT:
634       pinf:
635         return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
636       default:
637       div_zero:
638         PPL_ASSERT(To_Policy::check_div_zero);
639         return assign_nan<To_Policy>(to, V_DIV_ZERO);
640       }
641     }
642   }
643   else {
644     if (is_minf<From2_Policy>(y) || is_pinf<From2_Policy>(y)) {
645       to = 0;
646       return V_EQ;
647     }
648     else {
649     native:
650       return idiv<To_Policy, From1_Policy, From2_Policy>(to, x, y, dir);
651     }
652   }
653 }
654 
655 
656 template <typename To_Policy, typename From1_Policy, typename From2_Policy,
657           typename To, typename From1, typename From2>
658 inline Result
rem_ext(To & to,const From1 & x,const From2 & y,Rounding_Dir dir)659 rem_ext(To& to, const From1& x, const From2& y, Rounding_Dir dir) {
660   if (!ext_to_handle<From1_Policy>(x) && !ext_to_handle<From2_Policy>(y)) {
661     goto native;
662   }
663   if (is_nan<From1_Policy>(x) || is_nan<From2_Policy>(y)) {
664     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
665   }
666   else if (CHECK_P(To_Policy::check_inf_mod, is_minf<From1_Policy>(x)
667                    || is_pinf<From1_Policy>(x))) {
668     return assign_nan<To_Policy>(to, V_INF_MOD);
669   }
670   else {
671     if (is_minf<From1_Policy>(y) || is_pinf<From2_Policy>(y)) {
672       to = x;
673       return V_EQ;
674     }
675     else {
676     native:
677       return rem<To_Policy, From1_Policy, From2_Policy>(to, x, y, dir);
678     }
679   }
680 }
681 
682 template <typename To_Policy, typename From_Policy,
683           typename To, typename From>
684 inline Result
add_2exp_ext(To & to,const From & x,unsigned int exp,Rounding_Dir dir)685 add_2exp_ext(To& to, const From& x, unsigned int exp, Rounding_Dir dir) {
686   if (!ext_to_handle<From_Policy>(x)) {
687     goto native;
688   }
689   if (is_nan<From_Policy>(x)) {
690     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
691   }
692   else if (is_minf<From_Policy>(x)) {
693     return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
694   }
695   else if (is_pinf<From_Policy>(x)) {
696     return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
697   }
698   else {
699   native:
700     return add_2exp<To_Policy, From_Policy>(to, x, exp, dir);
701   }
702 }
703 
704 template <typename To_Policy, typename From_Policy,
705           typename To, typename From>
706 inline Result
sub_2exp_ext(To & to,const From & x,unsigned int exp,Rounding_Dir dir)707 sub_2exp_ext(To& to, const From& x, unsigned int exp, Rounding_Dir dir) {
708   if (!ext_to_handle<From_Policy>(x)) {
709     goto native;
710   }
711   if (is_nan<From_Policy>(x)) {
712     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
713   }
714   else if (is_minf<From_Policy>(x)) {
715     return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
716   }
717   else if (is_pinf<From_Policy>(x)) {
718     return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
719   }
720   else {
721   native:
722     return sub_2exp<To_Policy, From_Policy>(to, x, exp, dir);
723   }
724 }
725 
726 template <typename To_Policy, typename From_Policy,
727           typename To, typename From>
728 inline Result
mul_2exp_ext(To & to,const From & x,unsigned int exp,Rounding_Dir dir)729 mul_2exp_ext(To& to, const From& x, unsigned int exp, Rounding_Dir dir) {
730   if (!ext_to_handle<From_Policy>(x)) {
731     goto native;
732   }
733   if (is_nan<From_Policy>(x)) {
734     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
735   }
736   else if (is_minf<From_Policy>(x)) {
737     return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
738   }
739   else if (is_pinf<From_Policy>(x)) {
740     return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
741   }
742   else {
743   native:
744     return mul_2exp<To_Policy, From_Policy>(to, x, exp, dir);
745   }
746 }
747 
748 template <typename To_Policy, typename From_Policy,
749           typename To, typename From>
750 inline Result
div_2exp_ext(To & to,const From & x,unsigned int exp,Rounding_Dir dir)751 div_2exp_ext(To& to, const From& x, unsigned int exp, Rounding_Dir dir) {
752   if (!ext_to_handle<From_Policy>(x)) {
753     goto native;
754   }
755   if (is_nan<From_Policy>(x)) {
756     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
757   }
758   else if (is_minf<From_Policy>(x)) {
759     return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
760   }
761   else if (is_pinf<From_Policy>(x)) {
762     return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
763   }
764   else {
765   native:
766     return div_2exp<To_Policy, From_Policy>(to, x, exp, dir);
767   }
768 }
769 
770 template <typename To_Policy, typename From_Policy,
771           typename To, typename From>
772 inline Result
smod_2exp_ext(To & to,const From & x,unsigned int exp,Rounding_Dir dir)773 smod_2exp_ext(To& to, const From& x, unsigned int exp, Rounding_Dir dir) {
774   if (!ext_to_handle<From_Policy>(x)) {
775     goto native;
776   }
777   if (is_nan<From_Policy>(x)) {
778     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
779   }
780   else if (CHECK_P(To_Policy::check_inf_mod, is_minf<From_Policy>(x)
781                    || is_pinf<From_Policy>(x))) {
782     return assign_nan<To_Policy>(to, V_INF_MOD);
783   }
784   else {
785   native:
786     return smod_2exp<To_Policy, From_Policy>(to, x, exp, dir);
787   }
788 }
789 
790 template <typename To_Policy, typename From_Policy,
791           typename To, typename From>
792 inline Result
umod_2exp_ext(To & to,const From & x,unsigned int exp,Rounding_Dir dir)793 umod_2exp_ext(To& to, const From& x, unsigned int exp, Rounding_Dir dir) {
794   if (!ext_to_handle<From_Policy>(x)) {
795     goto native;
796   }
797   if (is_nan<From_Policy>(x)) {
798     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
799   }
800   else if (CHECK_P(To_Policy::check_inf_mod, is_minf<From_Policy>(x)
801                    || is_pinf<From_Policy>(x))) {
802     return assign_nan<To_Policy>(to, V_INF_MOD);
803   }
804   else {
805   native:
806     return umod_2exp<To_Policy, From_Policy>(to, x, exp, dir);
807   }
808 }
809 
810 template <typename To_Policy, typename From_Policy,
811           typename To, typename From>
812 inline Result
sqrt_ext(To & to,const From & x,Rounding_Dir dir)813 sqrt_ext(To& to, const From& x, Rounding_Dir dir) {
814   if (!ext_to_handle<From_Policy>(x)) {
815     goto native;
816   }
817   if (is_nan<From_Policy>(x)) {
818     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
819   }
820   else if (is_minf<From_Policy>(x)) {
821     return assign_nan<To_Policy>(to, V_SQRT_NEG);
822   }
823   else if (is_pinf<From_Policy>(x)) {
824     return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
825   }
826   else {
827   native:
828     return sqrt<To_Policy, From_Policy>(to, x, dir);
829   }
830 }
831 
832 template <typename To_Policy, typename From1_Policy, typename From2_Policy,
833           typename To, typename From1, typename From2>
834 inline Result
gcd_ext(To & to,const From1 & x,const From2 & y,Rounding_Dir dir)835 gcd_ext(To& to, const From1& x, const From2& y, Rounding_Dir dir) {
836   if (is_nan<From1_Policy>(x) || is_nan<From2_Policy>(y)) {
837     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
838   }
839   else if (is_minf<From1_Policy>(x) || is_pinf<From1_Policy>(x)) {
840     return abs_ext<To_Policy, From2_Policy>(to, y, dir);
841   }
842   else if (is_minf<From2_Policy>(y) || is_pinf<From2_Policy>(y)) {
843     return abs_ext<To_Policy, From1_Policy>(to, x, dir);
844   }
845   else {
846     return gcd<To_Policy, From1_Policy, From2_Policy>(to, x, y, dir);
847   }
848 }
849 
850 template <typename To1_Policy, typename To2_Policy, typename To3_Policy,
851           typename From1_Policy, typename From2_Policy,
852           typename To1, typename To2, typename To3,
853           typename From1, typename From2>
854 inline Result
gcdext_ext(To1 & to,To2 & s,To3 & t,const From1 & x,const From2 & y,Rounding_Dir dir)855 gcdext_ext(To1& to, To2& s, To3& t, const From1& x, const From2& y,
856            Rounding_Dir dir) {
857   if (is_nan<From1_Policy>(x) || is_nan<From2_Policy>(y)) {
858     return assign_special<To1_Policy>(to, VC_NAN, ROUND_IGNORE);
859   }
860   else if (is_minf<From1_Policy>(x) || is_pinf<From1_Policy>(x)) {
861     s = 0;
862     t = y > 0 ? -1 : 1;
863     return abs_ext<To1_Policy, From2_Policy>(to, y, dir);
864   }
865   else if (is_minf<From2_Policy>(y) || is_pinf<From2_Policy>(y)) {
866     s = x > 0 ? -1 : 1;
867     t = 0;
868     return abs_ext<To1_Policy, From1_Policy>(to, x, dir);
869   }
870   else {
871     return gcdext<To1_Policy, To2_Policy, To3_Policy, From1_Policy, From2_Policy>(to, s, t, x, y, dir);
872   }
873 }
874 
875 template <typename To_Policy, typename From1_Policy, typename From2_Policy,
876           typename To, typename From1, typename From2>
877 inline Result
lcm_ext(To & to,const From1 & x,const From2 & y,Rounding_Dir dir)878 lcm_ext(To& to, const From1& x, const From2& y, Rounding_Dir dir) {
879   if (is_nan<From1_Policy>(x) || is_nan<From2_Policy>(y)) {
880     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
881   }
882   else if (is_minf<From1_Policy>(x) || is_pinf<From1_Policy>(x)
883            || is_minf<From2_Policy>(y) || is_pinf<From2_Policy>(y)) {
884     return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
885   }
886   else {
887     return lcm<To_Policy, From1_Policy, From2_Policy>(to, x, y, dir);
888   }
889 }
890 
891 template <typename Policy1, typename Policy2,
892           typename Type1, typename Type2>
893 inline Result_Relation
cmp_ext(const Type1 & x,const Type2 & y)894 cmp_ext(const Type1& x, const Type2& y) {
895   if (!ext_to_handle<Policy1>(x) && !ext_to_handle<Policy2>(y)) {
896     goto native;
897   }
898   if (is_nan<Policy1>(x) || is_nan<Policy2>(y)) {
899     return VR_EMPTY;
900   }
901   else if (is_minf<Policy1>(x)) {
902     return is_minf<Policy2>(y) ? VR_EQ : VR_LT;
903   }
904   else if (is_pinf<Policy1>(x)) {
905     return is_pinf<Policy2>(y) ? VR_EQ : VR_GT;
906   }
907   else {
908     if (is_minf<Policy2>(y)) {
909       return VR_GT;
910     }
911     if (is_pinf<Policy2>(y)) {
912       return VR_LT;
913     }
914   native:
915     return cmp<Policy1, Policy2>(x, y);
916   }
917 }
918 
919 template <typename Policy1, typename Policy2,
920           typename Type1, typename Type2>
921 inline bool
lt_ext(const Type1 & x,const Type2 & y)922 lt_ext(const Type1& x, const Type2& y) {
923   if (!ext_to_handle<Policy1>(x) && !ext_to_handle<Policy2>(y)) {
924     goto native;
925   }
926   if (is_nan<Policy1>(x) || is_nan<Policy2>(y)) {
927     return false;
928   }
929   if (is_pinf<Policy1>(x) || is_minf<Policy2>(y)) {
930     return false;
931   }
932   if (is_minf<Policy1>(x) || is_pinf<Policy2>(y)) {
933     return true;
934   }
935  native:
936   return lt_p<Policy1, Policy2>(x, y);
937 }
938 
939 template <typename Policy1, typename Policy2,
940           typename Type1, typename Type2>
941 inline bool
gt_ext(const Type1 & x,const Type2 & y)942 gt_ext(const Type1& x, const Type2& y) {
943   return lt_ext<Policy1, Policy2>(y, x);
944 }
945 
946 template <typename Policy1, typename Policy2,
947           typename Type1, typename Type2>
948 inline bool
le_ext(const Type1 & x,const Type2 & y)949 le_ext(const Type1& x, const Type2& y) {
950   if (!ext_to_handle<Policy1>(x) && !ext_to_handle<Policy2>(y)) {
951     goto native;
952   }
953   if (is_nan<Policy1>(x) || is_nan<Policy2>(y)) {
954     return false;
955   }
956   if (is_minf<Policy1>(x) || is_pinf<Policy2>(y)) {
957     return true;
958   }
959   if (is_pinf<Policy1>(x) || is_minf<Policy2>(y)) {
960     return false;
961   }
962  native:
963   return le_p<Policy1, Policy2>(x, y);
964 }
965 
966 template <typename Policy1, typename Policy2,
967           typename Type1, typename Type2>
968 inline bool
ge_ext(const Type1 & x,const Type2 & y)969 ge_ext(const Type1& x, const Type2& y) {
970   return le_ext<Policy1, Policy2>(y, x);
971 }
972 
973 template <typename Policy1, typename Policy2,
974           typename Type1, typename Type2>
975 inline bool
eq_ext(const Type1 & x,const Type2 & y)976 eq_ext(const Type1& x, const Type2& y) {
977   if (!ext_to_handle<Policy1>(x) && !ext_to_handle<Policy2>(y)) {
978     goto native;
979   }
980   if (is_nan<Policy1>(x) || is_nan<Policy2>(y)) {
981     return false;
982   }
983   if (is_minf<Policy1>(x)) {
984     return is_minf<Policy2>(y);
985   }
986   if (is_pinf<Policy1>(x)) {
987     return is_pinf<Policy2>(y);
988   }
989   else if (is_minf<Policy2>(y) || is_pinf<Policy2>(y)) {
990     return false;
991   }
992  native:
993   return eq_p<Policy1, Policy2>(x, y);
994 }
995 
996 template <typename Policy1, typename Policy2,
997           typename Type1, typename Type2>
998 inline bool
ne_ext(const Type1 & x,const Type2 & y)999 ne_ext(const Type1& x, const Type2& y) {
1000   return !eq_ext<Policy1, Policy2>(x, y);
1001 }
1002 
1003 template <typename Policy, typename Type>
1004 inline Result
output_ext(std::ostream & os,const Type & x,const Numeric_Format & format,Rounding_Dir dir)1005 output_ext(std::ostream& os, const Type& x,
1006            const Numeric_Format& format, Rounding_Dir dir) {
1007   if (!ext_to_handle<Policy>(x)) {
1008     goto native;
1009   }
1010   if (is_nan<Policy>(x)) {
1011     os << "nan";
1012     return V_NAN;
1013   }
1014   if (is_minf<Policy>(x)) {
1015     os << "-inf";
1016     return V_EQ;
1017   }
1018   if (is_pinf<Policy>(x)) {
1019     os << "+inf";
1020     return V_EQ;
1021   }
1022  native:
1023   return output<Policy>(os, x, format, dir);
1024 }
1025 
1026 template <typename To_Policy, typename To>
1027 inline Result
input_ext(To & to,std::istream & is,Rounding_Dir dir)1028 input_ext(To& to, std::istream& is, Rounding_Dir dir) {
1029   return input<To_Policy>(to, is, dir);
1030 }
1031 
1032 } // namespace Checked
1033 
1034 } // namespace Parma_Polyhedra_Library
1035 
1036 #endif // !defined(PPL_checked_ext_defs_hh)
1037