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