1 /* Specialized "checked" functions for native floating-point 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_float_inlines_hh
25 #define PPL_checked_float_inlines_hh 1
26 
27 #include "compiler.hh"
28 #include <cmath>
29 
30 namespace Parma_Polyhedra_Library {
31 
32 namespace Checked {
33 
34 inline float
multiply_add(float x,float y,float z)35 multiply_add(float x, float y, float z) {
36 #if PPL_HAVE_DECL_FMAF && defined(FP_FAST_FMAF) \
37   && !defined(__alpha) && !defined(__FreeBSD__)
38   return fmaf(x, y, z);
39 #else
40   return x*y + z;
41 #endif
42 }
43 
44 inline double
multiply_add(double x,double y,double z)45 multiply_add(double x, double y, double z) {
46 #if PPL_HAVE_DECL_FMA && defined(FP_FAST_FMA) \
47   && !defined(__alpha) && !defined(__FreeBSD__)
48   return fma(x, y, z);
49 #else
50   return x*y + z;
51 #endif
52 }
53 
54 inline long double
multiply_add(long double x,long double y,long double z)55 multiply_add(long double x, long double y, long double z) {
56 #if PPL_HAVE_DECL_FMAL && defined(FP_FAST_FMAL) \
57   && !defined(__alpha) && !defined(__FreeBSD__)
58   return fmal(x, y, z);
59 #else
60   return x*y + z;
61 #endif
62 }
63 
64 #if PPL_HAVE_DECL_RINTF
65 inline float
round_to_integer(float x)66 round_to_integer(float x) {
67   return rintf(x);
68 }
69 #endif
70 
71 inline double
round_to_integer(double x)72 round_to_integer(double x) {
73   return rint(x);
74 }
75 
76 #if PPL_HAVE_DECL_RINTL
77 inline long double
round_to_integer(long double x)78 round_to_integer(long double x) {
79   return rintl(x);
80 }
81 #elif !PPL_CXX_PROVIDES_PROPER_LONG_DOUBLE
82 // If proper long doubles are not provided, this is most likely
83 // because long double and double are the same type: use rint().
84 inline long double
round_to_integer(long double x)85 round_to_integer(long double x) {
86   return rint(x);
87 }
88 #elif defined(__i386__) && (defined(__GNUC__) || defined(__INTEL_COMPILER))
89 // On Cygwin, we have proper long doubles but rintl() is not defined:
90 // luckily, one machine instruction is enough to save the day.
91 inline long double
round_to_integer(long double x)92 round_to_integer(long double x) {
93   long double i;
94   __asm__ ("frndint" : "=t" (i) : "0" (x));
95   return i;
96 }
97 #endif
98 
99 inline bool
fpu_direct_rounding(Rounding_Dir dir)100 fpu_direct_rounding(Rounding_Dir dir) {
101   return round_direct(dir) || round_not_requested(dir);
102 }
103 
104 inline bool
fpu_inverse_rounding(Rounding_Dir dir)105 fpu_inverse_rounding(Rounding_Dir dir) {
106   return round_inverse(dir);
107 }
108 
109 // The FPU mode is "round down".
110 //
111 // The result of the rounded down multiplication is thus computed directly.
112 //
113 //   a = 0.3
114 //   b = 0.1
115 //   c_i = a * b = 0.03
116 //   c = c_i = 0.0
117 //
118 // To obtain the result of the rounded up multiplication
119 // we do -(-a * b).
120 //
121 //   a = 0.3
122 //   b = 0.1
123 //   c_i = -a * b = -0.03
124 //
125 // Here c_i should be forced to lose excess precision, otherwise the
126 // FPU will truncate using the rounding mode in force, which is "round down".
127 //
128 //   c_i = -c_i = 0.03
129 //   c = c_i = 0.0
130 //
131 // Wrong result: we should have obtained c = 0.1.
132 
133 inline void
limit_precision(const float & v)134 limit_precision(const float& v) {
135   PPL_CC_FLUSH(v);
136 }
137 
138 inline void
limit_precision(const double & v)139 limit_precision(const double& v) {
140   PPL_CC_FLUSH(v);
141 }
142 
143 inline void
limit_precision(const long double &)144 limit_precision(const long double&) {
145 }
146 
147 template <typename Policy, typename T>
148 inline Result
classify_float(const T v,bool nan,bool inf,bool sign)149 classify_float(const T v, bool nan, bool inf, bool sign) {
150   Float<T> f(v);
151   if ((nan || sign) && CHECK_P(Policy::has_nan, f.u.binary.is_nan())) {
152     return V_NAN;
153   }
154   if (inf) {
155     if (Policy::has_infinity) {
156       int sign_inf = f.u.binary.inf_sign();
157       if (sign_inf < 0) {
158         return V_EQ_MINUS_INFINITY;
159       }
160       if (sign_inf > 0) {
161         return V_EQ_PLUS_INFINITY;
162       }
163     }
164     else {
165       PPL_ASSERT(f.u.binary.inf_sign() == 0);
166     }
167   }
168   if (sign) {
169     if (v < 0) {
170       return V_LT;
171     }
172     if (v > 0) {
173       return V_GT;
174     }
175     return V_EQ;
176   }
177   return V_LGE;
178 }
179 
180 template <typename Policy, typename T>
181 inline bool
is_nan_float(const T v)182 is_nan_float(const T v) {
183   Float<T> f(v);
184   return CHECK_P(Policy::has_nan, f.u.binary.is_nan());
185 }
186 
187 template <typename Policy, typename T>
188 inline bool
is_inf_float(const T v)189 is_inf_float(const T v) {
190   Float<T> f(v);
191   return CHECK_P(Policy::has_infinity, (f.u.binary.inf_sign() != 0));
192 }
193 template <typename Policy, typename T>
194 inline bool
is_minf_float(const T v)195 is_minf_float(const T v) {
196   Float<T> f(v);
197   return CHECK_P(Policy::has_infinity, (f.u.binary.inf_sign() < 0));
198 }
199 
200 template <typename Policy, typename T>
201 inline bool
is_pinf_float(const T v)202 is_pinf_float(const T v) {
203   Float<T> f(v);
204   return CHECK_P(Policy::has_infinity, (f.u.binary.inf_sign() > 0));
205 }
206 
207 
208 template <typename Policy, typename T>
209 inline bool
is_int_float(const T v)210 is_int_float(const T v) {
211   return round_to_integer(v) == v;
212 }
213 
214 template <typename Policy, typename T>
215 inline Result
assign_special_float(T & v,Result_Class c,Rounding_Dir)216 assign_special_float(T& v, Result_Class c, Rounding_Dir) {
217   PPL_ASSERT(c == VC_MINUS_INFINITY || c == VC_PLUS_INFINITY || c == VC_NAN);
218   switch (c) {
219   case VC_MINUS_INFINITY:
220     v = -HUGE_VAL;
221     return V_EQ_MINUS_INFINITY;
222   case VC_PLUS_INFINITY:
223     v = HUGE_VAL;
224     return V_EQ_PLUS_INFINITY;
225   case VC_NAN:
226     v = PPL_NAN;
227     return V_NAN;
228   default:
229     PPL_UNREACHABLE;
230     return V_NAN | V_UNREPRESENTABLE;
231   }
232 }
233 
234 template <typename T>
235 inline void
pred_float(T & v)236 pred_float(T& v) {
237   Float<T> f(v);
238   PPL_ASSERT(!f.u.binary.is_nan());
239   PPL_ASSERT(f.u.binary.inf_sign() >= 0);
240   if (f.u.binary.zero_sign() > 0) {
241     f.u.binary.negate();
242     f.u.binary.inc();
243   }
244   else if (f.u.binary.sign_bit()) {
245     f.u.binary.inc();
246   }
247   else {
248     f.u.binary.dec();
249   }
250   v = f.value();
251 }
252 
253 template <typename T>
254 inline void
succ_float(T & v)255 succ_float(T& v) {
256   Float<T> f(v);
257   PPL_ASSERT(!f.u.binary.is_nan());
258   PPL_ASSERT(f.u.binary.inf_sign() <= 0);
259   if (f.u.binary.zero_sign() < 0) {
260     f.u.binary.negate();
261     f.u.binary.inc();
262   }
263   else if (!f.u.binary.sign_bit()) {
264     f.u.binary.inc();
265   }
266   else {
267     f.u.binary.dec();
268   }
269   v = f.value();
270 }
271 
272 template <typename Policy, typename To>
273 inline Result
round_lt_float(To & to,Rounding_Dir dir)274 round_lt_float(To& to, Rounding_Dir dir) {
275   if (round_down(dir)) {
276     pred_float(to);
277     return V_GT;
278   }
279   return V_LT;
280 }
281 
282 template <typename Policy, typename To>
283 inline Result
round_gt_float(To & to,Rounding_Dir dir)284 round_gt_float(To& to, Rounding_Dir dir) {
285   if (round_up(dir)) {
286     succ_float(to);
287     return V_LT;
288   }
289   return V_GT;
290 }
291 
292 
293 template <typename Policy>
294 inline void
prepare_inexact(Rounding_Dir dir)295 prepare_inexact(Rounding_Dir dir) {
296   if (Policy::fpu_check_inexact
297       && !round_not_needed(dir) && round_strict_relation(dir)) {
298     fpu_reset_inexact();
299   }
300 }
301 
302 template <typename Policy>
303 inline Result
result_relation(Rounding_Dir dir)304 result_relation(Rounding_Dir dir) {
305   if (Policy::fpu_check_inexact
306       && !round_not_needed(dir) && round_strict_relation(dir)) {
307     switch (fpu_check_inexact()) {
308     case 0:
309       return V_EQ;
310     case -1:
311       goto unknown;
312     case 1:
313       break;
314     }
315     switch (round_dir(dir)) {
316     case ROUND_DOWN:
317       return V_GT;
318     case ROUND_UP:
319       return V_LT;
320     default:
321       return V_NE;
322     }
323   }
324   else {
325   unknown:
326     switch (round_dir(dir)) {
327     case ROUND_DOWN:
328       return V_GE;
329     case ROUND_UP:
330       return V_LE;
331     default:
332       return V_LGE;
333     }
334   }
335 }
336 
337 template <typename To_Policy, typename From_Policy, typename To, typename From>
338 inline Result
assign_float_float_exact(To & to,const From from,Rounding_Dir)339 assign_float_float_exact(To& to, const From from, Rounding_Dir) {
340   if (To_Policy::fpu_check_nan_result && is_nan<From_Policy>(from)) {
341     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
342   }
343   to = from;
344   return V_EQ;
345 }
346 
347 template <typename To_Policy, typename From_Policy, typename To, typename From>
348 inline Result
assign_float_float_inexact(To & to,const From from,Rounding_Dir dir)349 assign_float_float_inexact(To& to, const From from, Rounding_Dir dir) {
350   if (To_Policy::fpu_check_nan_result && is_nan<From_Policy>(from)) {
351     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
352   }
353   prepare_inexact<To_Policy>(dir);
354   if (fpu_direct_rounding(dir)) {
355     to = from;
356   }
357   else if (fpu_inverse_rounding(dir)) {
358     From tmp = -from;
359     to = tmp;
360     limit_precision(to);
361     to = -to;
362   }
363   else {
364     fpu_rounding_control_word_type old
365       = fpu_save_rounding_direction(round_fpu_dir(dir));
366     limit_precision(from);
367     to = from;
368     limit_precision(to);
369     fpu_restore_rounding_direction(old);
370   }
371   return result_relation<To_Policy>(dir);
372 }
373 
374 template <typename To_Policy, typename From_Policy, typename To, typename From>
375 inline Result
assign_float_float(To & to,const From from,Rounding_Dir dir)376 assign_float_float(To& to, const From from, Rounding_Dir dir) {
377   if (sizeof(From) > sizeof(To)) {
378     return assign_float_float_inexact<To_Policy, From_Policy>(to, from, dir);
379   }
380   else {
381     return assign_float_float_exact<To_Policy, From_Policy>(to, from, dir);
382   }
383 }
384 
385 template <typename To_Policy, typename From_Policy, typename Type>
386 inline Result
floor_float(Type & to,const Type from,Rounding_Dir)387 floor_float(Type& to, const Type from, Rounding_Dir) {
388   if (To_Policy::fpu_check_nan_result && is_nan<From_Policy>(from)) {
389     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
390   }
391   if (fpu_direct_rounding(ROUND_DOWN)) {
392     to = round_to_integer(from);
393   }
394   else if (fpu_inverse_rounding(ROUND_DOWN)) {
395     to = round_to_integer(-from);
396     limit_precision(to);
397     to = -to;
398   }
399   else {
400     fpu_rounding_control_word_type old
401       = fpu_save_rounding_direction(round_fpu_dir(ROUND_DOWN));
402     limit_precision(from);
403     to = round_to_integer(from);
404     limit_precision(to);
405     fpu_restore_rounding_direction(old);
406   }
407   return V_EQ;
408 }
409 
410 template <typename To_Policy, typename From_Policy, typename Type>
411 inline Result
ceil_float(Type & to,const Type from,Rounding_Dir)412 ceil_float(Type& to, const Type from, Rounding_Dir) {
413   if (To_Policy::fpu_check_nan_result && is_nan<From_Policy>(from)) {
414     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
415   }
416   if (fpu_direct_rounding(ROUND_UP)) {
417     to = round_to_integer(from);
418   }
419   else if (fpu_inverse_rounding(ROUND_UP)) {
420     to = round_to_integer(-from);
421     limit_precision(to);
422     to = -to;
423   }
424   else {
425     fpu_rounding_control_word_type old
426       = fpu_save_rounding_direction(round_fpu_dir(ROUND_UP));
427     limit_precision(from);
428     to = round_to_integer(from);
429     limit_precision(to);
430     fpu_restore_rounding_direction(old);
431   }
432   return V_EQ;
433 }
434 
435 template <typename To_Policy, typename From_Policy, typename Type>
436 inline Result
trunc_float(Type & to,const Type from,Rounding_Dir dir)437 trunc_float(Type& to, const Type from, Rounding_Dir dir) {
438   if (To_Policy::fpu_check_nan_result && is_nan<From_Policy>(from)) {
439     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
440   }
441   if (from >= 0) {
442     return floor<To_Policy, From_Policy>(to, from, dir);
443   }
444   else {
445     return ceil<To_Policy, From_Policy>(to, from, dir);
446   }
447 }
448 
449 template <typename To_Policy, typename From_Policy, typename Type>
450 inline Result
neg_float(Type & to,const Type from,Rounding_Dir)451 neg_float(Type& to, const Type from, Rounding_Dir) {
452   if (To_Policy::fpu_check_nan_result && is_nan<From_Policy>(from)) {
453     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
454   }
455   to = -from;
456   return V_EQ;
457 }
458 
459 template <typename To_Policy, typename From1_Policy, typename From2_Policy,
460           typename Type>
461 inline Result
add_float(Type & to,const Type x,const Type y,Rounding_Dir dir)462 add_float(Type& to, const Type x, const Type y, Rounding_Dir dir) {
463   if (To_Policy::check_inf_add_inf
464       && is_inf_float<From1_Policy>(x) && x == -y) {
465     return assign_nan<To_Policy>(to, V_INF_ADD_INF);
466   }
467   prepare_inexact<To_Policy>(dir);
468   if (fpu_direct_rounding(dir)) {
469     to = x + y;
470   }
471   else if (fpu_inverse_rounding(dir)) {
472     to = -x - y;
473     limit_precision(to);
474     to = -to;
475   }
476   else {
477     fpu_rounding_control_word_type old
478       = fpu_save_rounding_direction(round_fpu_dir(dir));
479     limit_precision(x);
480     limit_precision(y);
481     to = x + y;
482     limit_precision(to);
483     fpu_restore_rounding_direction(old);
484   }
485   if (To_Policy::fpu_check_nan_result && is_nan<To_Policy>(to)) {
486     return V_NAN;
487   }
488   return result_relation<To_Policy>(dir);
489 }
490 
491 template <typename To_Policy, typename From1_Policy, typename From2_Policy,
492           typename Type>
493 inline Result
sub_float(Type & to,const Type x,const Type y,Rounding_Dir dir)494 sub_float(Type& to, const Type x, const Type y, Rounding_Dir dir) {
495   if (To_Policy::check_inf_sub_inf
496       && is_inf_float<From1_Policy>(x) && x == y) {
497     return assign_nan<To_Policy>(to, V_INF_SUB_INF);
498   }
499   prepare_inexact<To_Policy>(dir);
500   if (fpu_direct_rounding(dir)) {
501     to = x - y;
502   }
503   else if (fpu_inverse_rounding(dir)) {
504     to = y - x;
505     limit_precision(to);
506     to = -to;
507   }
508   else {
509     fpu_rounding_control_word_type old
510       = fpu_save_rounding_direction(round_fpu_dir(dir));
511     limit_precision(x);
512     limit_precision(y);
513     to = x - y;
514     limit_precision(to);
515     fpu_restore_rounding_direction(old);
516   }
517   if (To_Policy::fpu_check_nan_result && is_nan<To_Policy>(to)) {
518     return V_NAN;
519   }
520   return result_relation<To_Policy>(dir);
521 }
522 
523 template <typename To_Policy, typename From1_Policy, typename From2_Policy,
524           typename Type>
525 inline Result
mul_float(Type & to,const Type x,const Type y,Rounding_Dir dir)526 mul_float(Type& to, const Type x, const Type y, Rounding_Dir dir) {
527   if (To_Policy::check_inf_mul_zero
528       && ((x == 0 && is_inf_float<From2_Policy>(y))
529           ||
530           (y == 0 && is_inf_float<From1_Policy>(x)))) {
531     return assign_nan<To_Policy>(to, V_INF_MUL_ZERO);
532   }
533   prepare_inexact<To_Policy>(dir);
534   if (fpu_direct_rounding(dir)) {
535     to = x * y;
536   }
537   else if (fpu_inverse_rounding(dir)) {
538     to = x * -y;
539     limit_precision(to);
540     to = -to;
541   }
542   else {
543     fpu_rounding_control_word_type old
544       = fpu_save_rounding_direction(round_fpu_dir(dir));
545     limit_precision(x);
546     limit_precision(y);
547     to = x * y;
548     limit_precision(to);
549     fpu_restore_rounding_direction(old);
550   }
551   if (To_Policy::fpu_check_nan_result && is_nan<To_Policy>(to)) {
552     return V_NAN;
553   }
554   return result_relation<To_Policy>(dir);
555 }
556 
557 template <typename To_Policy, typename From1_Policy, typename From2_Policy,
558           typename Type>
559 inline Result
div_float(Type & to,const Type x,const Type y,Rounding_Dir dir)560 div_float(Type& to, const Type x, const Type y, Rounding_Dir dir) {
561   if (To_Policy::check_inf_div_inf
562       && is_inf_float<From1_Policy>(x) && is_inf_float<From2_Policy>(y)) {
563     return assign_nan<To_Policy>(to, V_INF_DIV_INF);
564   }
565   if (To_Policy::check_div_zero && y == 0) {
566     return assign_nan<To_Policy>(to, V_DIV_ZERO);
567   }
568   prepare_inexact<To_Policy>(dir);
569   if (fpu_direct_rounding(dir)) {
570     to = x / y;
571   }
572   else if (fpu_inverse_rounding(dir)) {
573     to = x / -y;
574     limit_precision(to);
575     to = -to;
576   }
577   else {
578     fpu_rounding_control_word_type old
579       = fpu_save_rounding_direction(round_fpu_dir(dir));
580     limit_precision(x);
581     limit_precision(y);
582     to = x / y;
583     limit_precision(to);
584     fpu_restore_rounding_direction(old);
585   }
586   if (To_Policy::fpu_check_nan_result && is_nan<To_Policy>(to)) {
587     return V_NAN;
588   }
589   return result_relation<To_Policy>(dir);
590 }
591 
592 template <typename To_Policy, typename From1_Policy, typename From2_Policy,
593           typename Type>
594 inline Result
idiv_float(Type & to,const Type x,const Type y,Rounding_Dir dir)595 idiv_float(Type& to, const Type x, const Type y, Rounding_Dir dir) {
596   Type temp;
597   // The inexact check is useless
598   dir = round_dir(dir);
599   Result r = div<To_Policy, From1_Policy, From2_Policy>(temp, x, y, dir);
600   if (result_class(r) != VC_NORMAL) {
601     to = temp;
602     return r;
603   }
604   Result r1 = trunc<To_Policy, To_Policy>(to, temp, ROUND_NOT_NEEDED);
605   PPL_ASSERT(r1 == V_EQ);
606   if (r == V_EQ || to != temp) {
607     return r1;
608   }
609   // FIXME: Prove that it is impossible to return a strict relation
610   return (dir == ROUND_UP) ? V_LE : V_GE;
611 }
612 
613 template <typename To_Policy, typename From1_Policy, typename From2_Policy,
614           typename Type>
615 inline Result
rem_float(Type & to,const Type x,const Type y,Rounding_Dir)616 rem_float(Type& to, const Type x, const Type y, Rounding_Dir) {
617   if (To_Policy::check_inf_mod && is_inf_float<From1_Policy>(x)) {
618     return assign_nan<To_Policy>(to, V_INF_MOD);
619   }
620   if (To_Policy::check_div_zero && y == 0) {
621     return assign_nan<To_Policy>(to, V_MOD_ZERO);
622   }
623   to = std::fmod(x, y);
624   if (To_Policy::fpu_check_nan_result && is_nan<To_Policy>(to)) {
625     return V_NAN;
626   }
627   return V_EQ;
628 }
629 
630 struct Float_2exp {
631   const_bool_nodef(has_nan, false);
632   const_bool_nodef(has_infinity, false);
633 };
634 
635 template <typename To_Policy, typename From_Policy, typename Type>
636 inline Result
add_2exp_float(Type & to,const Type x,unsigned int exp,Rounding_Dir dir)637 add_2exp_float(Type& to, const Type x, unsigned int exp, Rounding_Dir dir) {
638   if (To_Policy::fpu_check_nan_result && is_nan<From_Policy>(x)) {
639     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
640   }
641   PPL_ASSERT(exp < sizeof_to_bits(sizeof(unsigned long long)));
642   return
643     add<To_Policy, From_Policy, Float_2exp>(to,
644                                             x,
645                                             Type(1ULL << exp),
646                                             dir);
647 }
648 
649 template <typename To_Policy, typename From_Policy, typename Type>
650 inline Result
sub_2exp_float(Type & to,const Type x,unsigned int exp,Rounding_Dir dir)651 sub_2exp_float(Type& to, const Type x, unsigned int exp, Rounding_Dir dir) {
652   if (To_Policy::fpu_check_nan_result && is_nan<From_Policy>(x)) {
653     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
654   }
655   PPL_ASSERT(exp < sizeof_to_bits(sizeof(unsigned long long)));
656   return
657     sub<To_Policy, From_Policy, Float_2exp>(to,
658                                             x,
659                                             Type(1ULL << exp),
660                                             dir);
661 }
662 
663 template <typename To_Policy, typename From_Policy, typename Type>
664 inline Result
mul_2exp_float(Type & to,const Type x,unsigned int exp,Rounding_Dir dir)665 mul_2exp_float(Type& to, const Type x, unsigned int exp, Rounding_Dir dir) {
666   if (To_Policy::fpu_check_nan_result && is_nan<From_Policy>(x)) {
667     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
668   }
669   PPL_ASSERT(exp < sizeof_to_bits(sizeof(unsigned long long)));
670   return
671     mul<To_Policy, From_Policy, Float_2exp>(to,
672                                             x,
673                                             Type(1ULL << exp),
674                                             dir);
675 }
676 
677 template <typename To_Policy, typename From_Policy, typename Type>
678 inline Result
div_2exp_float(Type & to,const Type x,unsigned int exp,Rounding_Dir dir)679 div_2exp_float(Type& to, const Type x, unsigned int exp, Rounding_Dir dir) {
680   if (To_Policy::fpu_check_nan_result && is_nan<From_Policy>(x)) {
681     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
682   }
683   PPL_ASSERT(exp < sizeof_to_bits(sizeof(unsigned long long)));
684   return
685     div<To_Policy, From_Policy, Float_2exp>(to,
686                                             x,
687                                             Type(1ULL << exp),
688                                             dir);
689 }
690 
691 template <typename To_Policy, typename From_Policy, typename Type>
692 inline Result
smod_2exp_float(Type & to,const Type x,unsigned int exp,Rounding_Dir dir)693 smod_2exp_float(Type& to, const Type x, unsigned int exp, Rounding_Dir dir) {
694   if (To_Policy::fpu_check_nan_result && is_nan<From_Policy>(x)) {
695     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
696   }
697   if (To_Policy::check_inf_mod && is_inf_float<From_Policy>(x)) {
698     return assign_nan<To_Policy>(to, V_INF_MOD);
699   }
700   PPL_ASSERT(exp < sizeof_to_bits(sizeof(unsigned long long)));
701   Type m = 1ULL << exp;
702   rem_float<To_Policy, From_Policy, Float_2exp>(to, x, m, ROUND_IGNORE);
703   Type m2 = m / 2;
704   if (to < -m2) {
705     return add_float<To_Policy, From_Policy, Float_2exp>(to, to, m, dir);
706   }
707   else if (to >= m2) {
708     return sub_float<To_Policy, From_Policy, Float_2exp>(to, to, m, dir);
709   }
710   return V_EQ;
711 }
712 
713 template <typename To_Policy, typename From_Policy, typename Type>
714 inline Result
umod_2exp_float(Type & to,const Type x,unsigned int exp,Rounding_Dir dir)715 umod_2exp_float(Type& to, const Type x, unsigned int exp, Rounding_Dir dir) {
716   if (To_Policy::fpu_check_nan_result && is_nan<From_Policy>(x)) {
717     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
718   }
719   if (To_Policy::check_inf_mod && is_inf_float<From_Policy>(x)) {
720     return assign_nan<To_Policy>(to, V_INF_MOD);
721   }
722   PPL_ASSERT(exp < sizeof_to_bits(sizeof(unsigned long long)));
723   Type m = 1ULL << exp;
724   rem_float<To_Policy, From_Policy, Float_2exp>(to, x, m, ROUND_IGNORE);
725   if (to < 0) {
726     return add_float<To_Policy, From_Policy, Float_2exp>(to, to, m, dir);
727   }
728   return V_EQ;
729 }
730 
731 template <typename To_Policy, typename From_Policy, typename Type>
732 inline Result
abs_float(Type & to,const Type from,Rounding_Dir)733 abs_float(Type& to, const Type from, Rounding_Dir) {
734   if (To_Policy::fpu_check_nan_result && is_nan<From_Policy>(from)) {
735     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
736   }
737   to = std::abs(from);
738   return V_EQ;
739 }
740 
741 template <typename To_Policy, typename From_Policy, typename Type>
742 inline Result
sqrt_float(Type & to,const Type from,Rounding_Dir dir)743 sqrt_float(Type& to, const Type from, Rounding_Dir dir) {
744   if (To_Policy::fpu_check_nan_result && is_nan<From_Policy>(from)) {
745     return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
746   }
747   if (To_Policy::check_sqrt_neg && from < 0) {
748     return assign_nan<To_Policy>(to, V_SQRT_NEG);
749   }
750   prepare_inexact<To_Policy>(dir);
751   if (fpu_direct_rounding(dir)) {
752     to = std::sqrt(from);
753   }
754   else {
755     fpu_rounding_control_word_type old
756       = fpu_save_rounding_direction(round_fpu_dir(dir));
757     limit_precision(from);
758     to = std::sqrt(from);
759     limit_precision(to);
760     fpu_restore_rounding_direction(old);
761   }
762   return result_relation<To_Policy>(dir);
763 }
764 
765 template <typename Policy, typename Type>
766 inline Result_Relation
sgn_float(const Type x)767 sgn_float(const Type x) {
768   if (x > 0) {
769     return VR_GT;
770   }
771   if (x < 0) {
772     return VR_LT;
773   }
774   if (x == 0) {
775     return VR_EQ;
776   }
777   return VR_EMPTY;
778 }
779 
780 template <typename Policy1, typename Policy2, typename Type>
781 inline Result_Relation
cmp_float(const Type x,const Type y)782 cmp_float(const Type x, const Type y) {
783   if (x > y) {
784     return VR_GT;
785   }
786   if (x < y) {
787     return VR_LT;
788   }
789   if (x == y) {
790     return VR_EQ;
791   }
792   return VR_EMPTY;
793 }
794 
795 template <typename To_Policy, typename From_Policy, typename To, typename From>
796 inline Result
assign_float_int_inexact(To & to,const From from,Rounding_Dir dir)797 assign_float_int_inexact(To& to, const From from, Rounding_Dir dir) {
798   prepare_inexact<To_Policy>(dir);
799   if (fpu_direct_rounding(dir)) {
800     to = from;
801   }
802   else {
803     fpu_rounding_control_word_type old
804       = fpu_save_rounding_direction(round_fpu_dir(dir));
805     to = from;
806     limit_precision(to);
807     fpu_restore_rounding_direction(old);
808   }
809   return result_relation<To_Policy>(dir);
810 }
811 
812 template <typename To_Policy, typename From_Policy, typename To, typename From>
813 inline Result
assign_float_int(To & to,const From from,Rounding_Dir dir)814 assign_float_int(To& to, const From from, Rounding_Dir dir) {
815   if (sizeof_to_bits(sizeof(From)) > Float<To>::Binary::MANTISSA_BITS) {
816     return assign_float_int_inexact<To_Policy, From_Policy>(to, from, dir);
817   }
818   else {
819     return assign_exact<To_Policy, From_Policy>(to, from, dir);
820   }
821 }
822 
823 template <typename Policy, typename T>
824 inline Result
set_neg_overflow_float(T & to,Rounding_Dir dir)825 set_neg_overflow_float(T& to, Rounding_Dir dir) {
826   switch (round_dir(dir)) {
827   case ROUND_UP:
828     {
829       Float<T> f;
830       f.u.binary.set_max(true);
831       to = f.value();
832       return V_LT_INF;
833     }
834   case ROUND_DOWN: // Fall through.
835   case ROUND_IGNORE:
836     to = -HUGE_VAL;
837     return V_GT_MINUS_INFINITY;
838   default:
839     PPL_UNREACHABLE;
840     return V_GT_MINUS_INFINITY;
841   }
842 }
843 
844 template <typename Policy, typename T>
845 inline Result
set_pos_overflow_float(T & to,Rounding_Dir dir)846 set_pos_overflow_float(T& to, Rounding_Dir dir) {
847   switch (round_dir(dir)) {
848   case ROUND_DOWN:
849     {
850       Float<T> f;
851       f.u.binary.set_max(false);
852       to = f.value();
853       return V_GT_SUP;
854     }
855   case ROUND_UP: // Fall through.
856   case ROUND_IGNORE:
857     to = HUGE_VAL;
858     return V_LT_PLUS_INFINITY;
859   default:
860     PPL_UNREACHABLE;
861     return V_LT_PLUS_INFINITY;
862   }
863 }
864 
865 template <typename To_Policy, typename From_Policy, typename T>
866 inline Result
assign_float_mpz(T & to,const mpz_class & from,Rounding_Dir dir)867 assign_float_mpz(T& to, const mpz_class& from, Rounding_Dir dir) {
868   int sign = sgn(from);
869   if (sign == 0) {
870     to = 0;
871     return V_EQ;
872   }
873   mpz_srcptr from_z = from.get_mpz_t();
874   size_t exponent = mpz_sizeinbase(from_z, 2) - 1;
875   if (exponent > size_t(Float<T>::Binary::EXPONENT_MAX)) {
876     if (sign < 0) {
877       return set_neg_overflow_float<To_Policy>(to, dir);
878     }
879     else {
880       return set_pos_overflow_float<To_Policy>(to, dir);
881     }
882   }
883   unsigned long zeroes = mpn_scan1(from_z->_mp_d, 0);
884   size_t meaningful_bits = exponent - zeroes;
885   mpz_t mantissa;
886   mpz_init(mantissa);
887   if (exponent > Float<T>::Binary::MANTISSA_BITS) {
888     mpz_tdiv_q_2exp(mantissa,
889                     from_z,
890                     exponent - Float<T>::Binary::MANTISSA_BITS);
891   }
892   else {
893     mpz_mul_2exp(mantissa, from_z, Float<T>::Binary::MANTISSA_BITS - exponent);
894   }
895   Float<T> f;
896   f.u.binary.build(sign < 0, mantissa, static_cast<long>(exponent));
897   mpz_clear(mantissa);
898   to = f.value();
899   if (meaningful_bits > Float<T>::Binary::MANTISSA_BITS) {
900     if (sign < 0) {
901       return round_lt_float<To_Policy>(to, dir);
902     }
903     else {
904       return round_gt_float<To_Policy>(to, dir);
905     }
906   }
907   return V_EQ;
908 }
909 
910 template <typename To_Policy, typename From_Policy, typename T>
911 inline Result
assign_float_mpq(T & to,const mpq_class & from,Rounding_Dir dir)912 assign_float_mpq(T& to, const mpq_class& from, Rounding_Dir dir) {
913   const mpz_class& numer = from.get_num();
914   const mpz_class& denom = from.get_den();
915   if (denom == 1) {
916     return assign_float_mpz<To_Policy, From_Policy>(to, numer, dir);
917   }
918   mpz_srcptr numer_z = numer.get_mpz_t();
919   mpz_srcptr denom_z = denom.get_mpz_t();
920   int sign = sgn(numer);
921   long exponent = static_cast<long>(mpz_sizeinbase(numer_z, 2))
922     - static_cast<long>(mpz_sizeinbase(denom_z, 2));
923   if (exponent < Float<T>::Binary::EXPONENT_MIN_DENORM) {
924     to = 0;
925   inexact:
926     if (sign < 0) {
927       return round_lt_float<To_Policy>(to, dir);
928     }
929     else {
930       return round_gt_float<To_Policy>(to, dir);
931     }
932   }
933   if (exponent > Float<T>::Binary::EXPONENT_MAX + 1) {
934   overflow:
935     if (sign < 0) {
936       return set_neg_overflow_float<To_Policy>(to, dir);
937     }
938     else {
939       return set_pos_overflow_float<To_Policy>(to, dir);
940     }
941   }
942   unsigned int needed_bits = Float<T>::Binary::MANTISSA_BITS + 1;
943   if (exponent < Float<T>::Binary::EXPONENT_MIN) {
944     long diff = Float<T>::Binary::EXPONENT_MIN - exponent;
945     needed_bits -= static_cast<unsigned int>(diff);
946   }
947   mpz_t mantissa;
948   mpz_init(mantissa);
949   {
950     long shift = static_cast<long>(needed_bits) - exponent;
951     if (shift > 0) {
952       mpz_mul_2exp(mantissa, numer_z, static_cast<unsigned long>(shift));
953       numer_z = mantissa;
954     }
955     else if (shift < 0) {
956       shift = -shift;
957       mpz_mul_2exp(mantissa, denom_z, static_cast<unsigned long>(shift));
958       denom_z = mantissa;
959     }
960   }
961   mpz_t r;
962   mpz_init(r);
963   mpz_tdiv_qr(mantissa, r, numer_z, denom_z);
964   size_t bits = mpz_sizeinbase(mantissa, 2);
965   bool inexact = (mpz_sgn(r) != 0);
966   mpz_clear(r);
967   if (bits == needed_bits + 1) {
968     inexact = (inexact || mpz_odd_p(mantissa));
969     mpz_tdiv_q_2exp(mantissa, mantissa, 1);
970   }
971   else {
972     --exponent;
973   }
974   if (exponent > Float<T>::Binary::EXPONENT_MAX) {
975     mpz_clear(mantissa);
976     goto overflow;
977   }
978   else if (exponent < Float<T>::Binary::EXPONENT_MIN - 1) {
979     // Denormalized.
980     exponent = Float<T>::Binary::EXPONENT_MIN - 1;
981   }
982   Float<T> f;
983   f.u.binary.build(sign < 0, mantissa, exponent);
984   mpz_clear(mantissa);
985   to = f.value();
986   if (inexact) {
987     goto inexact;
988   }
989   return V_EQ;
990 }
991 
992 template <typename To_Policy, typename From1_Policy, typename From2_Policy,
993           typename Type>
994 inline Result
add_mul_float(Type & to,const Type x,const Type y,Rounding_Dir dir)995 add_mul_float(Type& to, const Type x, const Type y, Rounding_Dir dir) {
996   if (To_Policy::check_inf_mul_zero
997       && ((x == 0 && is_inf_float<From2_Policy>(y))
998           ||
999           (y == 0 && is_inf_float<From1_Policy>(x)))) {
1000     return assign_nan<To_Policy>(to, V_INF_MUL_ZERO);
1001   }
1002   // FIXME: missing check_inf_add_inf
1003   prepare_inexact<To_Policy>(dir);
1004   if (fpu_direct_rounding(dir)) {
1005     to = multiply_add(x, y, to);
1006   }
1007   else if (fpu_inverse_rounding(dir)) {
1008     to = multiply_add(-x, y, -to);
1009     limit_precision(to);
1010     to = -to;
1011   }
1012   else {
1013     fpu_rounding_control_word_type old
1014       = fpu_save_rounding_direction(round_fpu_dir(dir));
1015     limit_precision(x);
1016     limit_precision(y);
1017     limit_precision(to);
1018     to = multiply_add(x, y, to);
1019     limit_precision(to);
1020     fpu_restore_rounding_direction(old);
1021   }
1022   if (To_Policy::fpu_check_nan_result && is_nan<To_Policy>(to)) {
1023     return V_NAN;
1024   }
1025   return result_relation<To_Policy>(dir);
1026 }
1027 
1028 template <typename To_Policy, typename From1_Policy, typename From2_Policy, typename Type>
1029 inline Result
sub_mul_float(Type & to,const Type x,const Type y,Rounding_Dir dir)1030 sub_mul_float(Type& to, const Type x, const Type y, Rounding_Dir dir) {
1031   if (To_Policy::check_inf_mul_zero
1032       && ((x == 0 && is_inf_float<From2_Policy>(y))
1033           ||
1034           (y == 0 && is_inf_float<From1_Policy>(x)))) {
1035     return assign_nan<To_Policy>(to, V_INF_MUL_ZERO);
1036   }
1037   // FIXME: missing check_inf_add_inf
1038   prepare_inexact<To_Policy>(dir);
1039   if (fpu_direct_rounding(dir)) {
1040     to = multiply_add(x, -y, to);
1041   }
1042   else if (fpu_inverse_rounding(dir)) {
1043     to = multiply_add(x, y, -to);
1044     limit_precision(to);
1045     to = -to;
1046   }
1047   else {
1048     fpu_rounding_control_word_type old
1049       = fpu_save_rounding_direction(round_fpu_dir(dir));
1050     limit_precision(x);
1051     limit_precision(y);
1052     limit_precision(to);
1053     to = multiply_add(x, -y, to);
1054     limit_precision(to);
1055     fpu_restore_rounding_direction(old);
1056   }
1057   if (To_Policy::fpu_check_nan_result && is_nan<To_Policy>(to)) {
1058     return V_NAN;
1059   }
1060   return result_relation<To_Policy>(dir);
1061 }
1062 
1063 template <typename From>
1064 inline void
assign_mpq_numeric_float(mpq_class & to,const From from)1065 assign_mpq_numeric_float(mpq_class& to, const From from) {
1066   to = from;
1067 }
1068 
1069 template <>
1070 inline void
assign_mpq_numeric_float(mpq_class & to,const long double from)1071 assign_mpq_numeric_float(mpq_class& to, const long double from) {
1072   to = 0;
1073   if (from == 0.0L) {
1074     return;
1075   }
1076   mpz_class& num = to.get_num();
1077   mpz_class& den = to.get_den();
1078   int exp;
1079   long double n = std::frexp(from, &exp);
1080   bool neg = false;
1081   if (n < 0.0L) {
1082     neg = true;
1083     n = -n;
1084   }
1085   const long double mult = static_cast<long double>(ULONG_MAX) + 1.0L;
1086   const unsigned int bits = sizeof(unsigned long) * CHAR_BIT;
1087   while (true) {
1088     n *= mult;
1089     exp -= bits;
1090     const long double intpart = std::floor(n);
1091     num += static_cast<unsigned long>(intpart);
1092     n -= intpart;
1093     if (n == 0.0L) {
1094       break;
1095     }
1096     num <<= bits;
1097   }
1098   if (exp < 0) {
1099     den <<= -exp;
1100   }
1101   else {
1102     num <<= exp;
1103   }
1104   if (neg) {
1105     to = -to;
1106   }
1107   to.canonicalize();
1108 }
1109 
1110 template <typename Policy, typename Type>
1111 inline Result
output_float(std::ostream & os,const Type from,const Numeric_Format &,Rounding_Dir)1112 output_float(std::ostream& os, const Type from, const Numeric_Format&,
1113              Rounding_Dir) {
1114   if (from == 0) {
1115     os << "0";
1116   }
1117   else if (is_minf<Policy>(from)) {
1118     os << "-inf";
1119   }
1120   else if (is_pinf<Policy>(from)) {
1121     os << "+inf";
1122   }
1123   else if (is_nan<Policy>(from)) {
1124     os << "nan";
1125   }
1126   else {
1127     mpq_class q;
1128     assign_mpq_numeric_float(q, from);
1129     std::string s = float_mpq_to_string(q);
1130     os << s;
1131   }
1132   return V_EQ;
1133 }
1134 
1135 #if PPL_SUPPORTED_FLOAT
1136 PPL_SPECIALIZE_ASSIGN(assign_float_float_exact, float, float)
1137 #if PPL_SUPPORTED_DOUBLE
1138 PPL_SPECIALIZE_ASSIGN(assign_float_float, float, double)
1139 PPL_SPECIALIZE_ASSIGN(assign_float_float_exact, double, float)
1140 #endif
1141 #if PPL_SUPPORTED_LONG_DOUBLE
1142 PPL_SPECIALIZE_ASSIGN(assign_float_float, float, long double)
1143 PPL_SPECIALIZE_ASSIGN(assign_float_float_exact, long double, float)
1144 #endif
1145 #endif
1146 
1147 #if PPL_SUPPORTED_DOUBLE
1148 PPL_SPECIALIZE_ASSIGN(assign_float_float_exact, double, double)
1149 #if PPL_SUPPORTED_LONG_DOUBLE
1150 PPL_SPECIALIZE_ASSIGN(assign_float_float, double, long double)
1151 PPL_SPECIALIZE_ASSIGN(assign_float_float_exact, long double, double)
1152 #endif
1153 #endif
1154 
1155 #if PPL_SUPPORTED_LONG_DOUBLE
1156 PPL_SPECIALIZE_ASSIGN(assign_float_float_exact, long double, long double)
1157 #endif
1158 
1159 #if PPL_SUPPORTED_FLOAT
1160 PPL_SPECIALIZE_CLASSIFY(classify_float, float)
1161 PPL_SPECIALIZE_IS_NAN(is_nan_float, float)
1162 PPL_SPECIALIZE_IS_MINF(is_minf_float, float)
1163 PPL_SPECIALIZE_IS_PINF(is_pinf_float, float)
1164 PPL_SPECIALIZE_ASSIGN_SPECIAL(assign_special_float, float)
1165 PPL_SPECIALIZE_ASSIGN(assign_float_int, float, char)
1166 PPL_SPECIALIZE_ASSIGN(assign_float_int, float, signed char)
1167 PPL_SPECIALIZE_ASSIGN(assign_float_int, float, signed short)
1168 PPL_SPECIALIZE_ASSIGN(assign_float_int, float, signed int)
1169 PPL_SPECIALIZE_ASSIGN(assign_float_int, float, signed long)
1170 PPL_SPECIALIZE_ASSIGN(assign_float_int, float, signed long long)
1171 PPL_SPECIALIZE_ASSIGN(assign_float_int, float, unsigned char)
1172 PPL_SPECIALIZE_ASSIGN(assign_float_int, float, unsigned short)
1173 PPL_SPECIALIZE_ASSIGN(assign_float_int, float, unsigned int)
1174 PPL_SPECIALIZE_ASSIGN(assign_float_int, float, unsigned long)
1175 PPL_SPECIALIZE_ASSIGN(assign_float_int, float, unsigned long long)
1176 PPL_SPECIALIZE_ASSIGN(assign_float_mpz, float, mpz_class)
1177 PPL_SPECIALIZE_ASSIGN(assign_float_mpq, float, mpq_class)
1178 PPL_SPECIALIZE_COPY(copy_generic, float)
1179 PPL_SPECIALIZE_IS_INT(is_int_float, float)
1180 PPL_SPECIALIZE_FLOOR(floor_float, float, float)
1181 PPL_SPECIALIZE_CEIL(ceil_float, float, float)
1182 PPL_SPECIALIZE_TRUNC(trunc_float, float, float)
1183 PPL_SPECIALIZE_NEG(neg_float, float, float)
1184 PPL_SPECIALIZE_ABS(abs_float, float, float)
1185 PPL_SPECIALIZE_ADD(add_float, float, float, float)
1186 PPL_SPECIALIZE_SUB(sub_float, float, float, float)
1187 PPL_SPECIALIZE_MUL(mul_float, float, float, float)
1188 PPL_SPECIALIZE_DIV(div_float, float, float, float)
1189 PPL_SPECIALIZE_REM(rem_float, float, float, float)
1190 PPL_SPECIALIZE_ADD_2EXP(add_2exp_float, float, float)
1191 PPL_SPECIALIZE_SUB_2EXP(sub_2exp_float, float, float)
1192 PPL_SPECIALIZE_MUL_2EXP(mul_2exp_float, float, float)
1193 PPL_SPECIALIZE_DIV_2EXP(div_2exp_float, float, float)
1194 PPL_SPECIALIZE_SMOD_2EXP(smod_2exp_float, float, float)
1195 PPL_SPECIALIZE_UMOD_2EXP(umod_2exp_float, float, float)
1196 PPL_SPECIALIZE_SQRT(sqrt_float, float, float)
1197 PPL_SPECIALIZE_GCD(gcd_exact, float, float, float)
1198 PPL_SPECIALIZE_GCDEXT(gcdext_exact, float, float, float, float, float)
1199 PPL_SPECIALIZE_LCM(lcm_gcd_exact, float, float, float)
1200 PPL_SPECIALIZE_SGN(sgn_float, float)
1201 PPL_SPECIALIZE_CMP(cmp_float, float, float)
1202 PPL_SPECIALIZE_ADD_MUL(add_mul_float, float, float, float)
1203 PPL_SPECIALIZE_SUB_MUL(sub_mul_float, float, float, float)
1204 PPL_SPECIALIZE_INPUT(input_generic, float)
1205 PPL_SPECIALIZE_OUTPUT(output_float, float)
1206 #endif
1207 
1208 #if PPL_SUPPORTED_DOUBLE
1209 PPL_SPECIALIZE_CLASSIFY(classify_float, double)
1210 PPL_SPECIALIZE_IS_NAN(is_nan_float, double)
1211 PPL_SPECIALIZE_IS_MINF(is_minf_float, double)
1212 PPL_SPECIALIZE_IS_PINF(is_pinf_float, double)
1213 PPL_SPECIALIZE_ASSIGN_SPECIAL(assign_special_float, double)
1214 PPL_SPECIALIZE_ASSIGN(assign_float_int, double, char)
1215 PPL_SPECIALIZE_ASSIGN(assign_float_int, double, signed char)
1216 PPL_SPECIALIZE_ASSIGN(assign_float_int, double, signed short)
1217 PPL_SPECIALIZE_ASSIGN(assign_float_int, double, signed int)
1218 PPL_SPECIALIZE_ASSIGN(assign_float_int, double, signed long)
1219 PPL_SPECIALIZE_ASSIGN(assign_float_int, double, signed long long)
1220 PPL_SPECIALIZE_ASSIGN(assign_float_int, double, unsigned char)
1221 PPL_SPECIALIZE_ASSIGN(assign_float_int, double, unsigned short)
1222 PPL_SPECIALIZE_ASSIGN(assign_float_int, double, unsigned int)
1223 PPL_SPECIALIZE_ASSIGN(assign_float_int, double, unsigned long)
1224 PPL_SPECIALIZE_ASSIGN(assign_float_int, double, unsigned long long)
1225 PPL_SPECIALIZE_ASSIGN(assign_float_mpz, double, mpz_class)
1226 PPL_SPECIALIZE_ASSIGN(assign_float_mpq, double, mpq_class)
1227 PPL_SPECIALIZE_COPY(copy_generic, double)
1228 PPL_SPECIALIZE_IS_INT(is_int_float, double)
1229 PPL_SPECIALIZE_FLOOR(floor_float, double, double)
1230 PPL_SPECIALIZE_CEIL(ceil_float, double, double)
1231 PPL_SPECIALIZE_TRUNC(trunc_float, double, double)
1232 PPL_SPECIALIZE_NEG(neg_float, double, double)
1233 PPL_SPECIALIZE_ABS(abs_float, double, double)
1234 PPL_SPECIALIZE_ADD(add_float, double, double, double)
1235 PPL_SPECIALIZE_SUB(sub_float, double, double, double)
1236 PPL_SPECIALIZE_MUL(mul_float, double, double, double)
1237 PPL_SPECIALIZE_DIV(div_float, double, double, double)
1238 PPL_SPECIALIZE_REM(rem_float, double, double, double)
1239 PPL_SPECIALIZE_ADD_2EXP(add_2exp_float, double, double)
1240 PPL_SPECIALIZE_SUB_2EXP(sub_2exp_float, double, double)
1241 PPL_SPECIALIZE_MUL_2EXP(mul_2exp_float, double, double)
1242 PPL_SPECIALIZE_DIV_2EXP(div_2exp_float, double, double)
1243 PPL_SPECIALIZE_SMOD_2EXP(smod_2exp_float, double, double)
1244 PPL_SPECIALIZE_UMOD_2EXP(umod_2exp_float, double, double)
1245 PPL_SPECIALIZE_SQRT(sqrt_float, double, double)
1246 PPL_SPECIALIZE_GCD(gcd_exact, double, double, double)
1247 PPL_SPECIALIZE_GCDEXT(gcdext_exact, double, double, double, double, double)
1248 PPL_SPECIALIZE_LCM(lcm_gcd_exact, double, double, double)
1249 PPL_SPECIALIZE_SGN(sgn_float, double)
1250 PPL_SPECIALIZE_CMP(cmp_float, double, double)
1251 PPL_SPECIALIZE_ADD_MUL(add_mul_float, double, double, double)
1252 PPL_SPECIALIZE_SUB_MUL(sub_mul_float, double, double, double)
1253 PPL_SPECIALIZE_INPUT(input_generic, double)
1254 PPL_SPECIALIZE_OUTPUT(output_float, double)
1255 #endif
1256 
1257 #if PPL_SUPPORTED_LONG_DOUBLE
1258 PPL_SPECIALIZE_CLASSIFY(classify_float, long double)
1259 PPL_SPECIALIZE_IS_NAN(is_nan_float, long double)
1260 PPL_SPECIALIZE_IS_MINF(is_minf_float, long double)
1261 PPL_SPECIALIZE_IS_PINF(is_pinf_float, long double)
1262 PPL_SPECIALIZE_ASSIGN_SPECIAL(assign_special_float, long double)
1263 PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, char)
1264 PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, signed char)
1265 PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, signed short)
1266 PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, signed int)
1267 PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, signed long)
1268 PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, signed long long)
1269 PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, unsigned char)
1270 PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, unsigned short)
1271 PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, unsigned int)
1272 PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, unsigned long)
1273 PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, unsigned long long)
1274 PPL_SPECIALIZE_ASSIGN(assign_float_mpz, long double, mpz_class)
1275 PPL_SPECIALIZE_ASSIGN(assign_float_mpq, long double, mpq_class)
1276 PPL_SPECIALIZE_COPY(copy_generic, long double)
1277 PPL_SPECIALIZE_IS_INT(is_int_float, long double)
1278 PPL_SPECIALIZE_FLOOR(floor_float, long double, long double)
1279 PPL_SPECIALIZE_CEIL(ceil_float, long double, long double)
1280 PPL_SPECIALIZE_TRUNC(trunc_float, long double, long double)
1281 PPL_SPECIALIZE_NEG(neg_float, long double, long double)
1282 PPL_SPECIALIZE_ABS(abs_float, long double, long double)
1283 PPL_SPECIALIZE_ADD(add_float, long double, long double, long double)
1284 PPL_SPECIALIZE_SUB(sub_float, long double, long double, long double)
1285 PPL_SPECIALIZE_MUL(mul_float, long double, long double, long double)
1286 PPL_SPECIALIZE_DIV(div_float, long double, long double, long double)
1287 PPL_SPECIALIZE_REM(rem_float, long double, long double, long double)
1288 PPL_SPECIALIZE_ADD_2EXP(add_2exp_float, long double, long double)
1289 PPL_SPECIALIZE_SUB_2EXP(sub_2exp_float, long double, long double)
1290 PPL_SPECIALIZE_MUL_2EXP(mul_2exp_float, long double, long double)
1291 PPL_SPECIALIZE_DIV_2EXP(div_2exp_float, long double, long double)
1292 PPL_SPECIALIZE_SMOD_2EXP(smod_2exp_float, long double, long double)
1293 PPL_SPECIALIZE_UMOD_2EXP(umod_2exp_float, long double, long double)
1294 PPL_SPECIALIZE_SQRT(sqrt_float, long double, long double)
1295 PPL_SPECIALIZE_GCD(gcd_exact, long double, long double, long double)
1296 PPL_SPECIALIZE_GCDEXT(gcdext_exact, long double, long double, long double,
1297                   long double, long double)
1298 PPL_SPECIALIZE_LCM(lcm_gcd_exact, long double, long double, long double)
1299 PPL_SPECIALIZE_SGN(sgn_float, long double)
1300 PPL_SPECIALIZE_CMP(cmp_float, long double, long double)
1301 PPL_SPECIALIZE_ADD_MUL(add_mul_float, long double, long double, long double)
1302 PPL_SPECIALIZE_SUB_MUL(sub_mul_float, long double, long double, long double)
1303 PPL_SPECIALIZE_INPUT(input_generic, long double)
1304 PPL_SPECIALIZE_OUTPUT(output_float, long double)
1305 #endif
1306 
1307 } // namespace Checked
1308 
1309 } // namespace Parma_Polyhedra_Library
1310 
1311 #endif // !defined(PPL_checked_int_inlines_hh)
1312