summaryrefslogtreecommitdiff
path: root/src/checked_float.inlines.hh
diff options
context:
space:
mode:
Diffstat (limited to 'src/checked_float.inlines.hh')
-rw-r--r--src/checked_float.inlines.hh1179
1 files changed, 1179 insertions, 0 deletions
diff --git a/src/checked_float.inlines.hh b/src/checked_float.inlines.hh
new file mode 100644
index 000000000..24a795e2e
--- /dev/null
+++ b/src/checked_float.inlines.hh
@@ -0,0 +1,1179 @@
+/* Specialized "checked" functions for native floating-point numbers.
+ Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it>
+ Copyright (C) 2010-2011 BUGSENG srl (http://bugseng.com)
+
+This file is part of the Parma Polyhedra Library (PPL).
+
+The PPL is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+The PPL is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software Foundation,
+Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.
+
+For the most up-to-date information see the Parma Polyhedra Library
+site: http://www.cs.unipr.it/ppl/ . */
+
+#ifndef PPL_checked_float_inlines_hh
+#define PPL_checked_float_inlines_hh 1
+
+#include "compiler.hh"
+#ifndef __alpha
+#include <cmath>
+#endif
+
+namespace Parma_Polyhedra_Library {
+
+namespace Checked {
+
+inline float
+fma(float x, float y, float z) {
+#if PPL_HAVE_DECL_FMAF && defined(FP_FAST_FMAF) \
+ && !defined(__alpha) && !defined(__FreeBSD__)
+ return ::fmaf(x, y, z);
+#else
+ return x*y + z;
+#endif
+}
+
+inline double
+fma(double x, double y, double z) {
+#if PPL_HAVE_DECL_FMA && defined(FP_FAST_FMA) \
+ && !defined(__alpha) && !defined(__FreeBSD__)
+ return ::fma(x, y, z);
+#else
+ return x*y + z;
+#endif
+}
+
+inline long double
+fma(long double x, long double y, long double z) {
+#if PPL_HAVE_DECL_FMAL && defined(FP_FAST_FMAL) \
+ && !defined(__alpha) && !defined(__FreeBSD__)
+ return ::fmal(x, y, z);
+#else
+ return x*y + z;
+#endif
+}
+
+#if PPL_HAVE_DECL_RINTF
+inline float
+rint(float x) {
+ return ::rintf(x);
+}
+#endif
+
+inline double
+rint(double x) {
+ return ::rint(x);
+}
+
+#if PPL_HAVE_DECL_RINTL
+inline long double
+rint(long double x) {
+ return ::rintl(x);
+}
+#elif !PPL_CXX_PROVIDES_PROPER_LONG_DOUBLE
+// If proper long doubles are not provided, this is most likely
+// because long double and double are the same type: use rint().
+inline long double
+rint(long double x) {
+ return ::rint(x);
+}
+#elif defined(__i386__) && (defined(__GNUC__) || defined(__INTEL_COMPILER))
+// On Cygwin, we have proper long doubles but rintl() is not defined:
+// luckily, one machine instruction is enough to save the day.
+inline long double
+rint(long double x) {
+ long double i;
+ __asm__ ("frndint" : "=t" (i) : "0" (x));
+ return i;
+}
+#endif
+
+inline bool
+fpu_direct_rounding(Rounding_Dir dir) {
+ return round_direct(dir) || round_not_requested(dir);
+}
+
+inline bool
+fpu_inverse_rounding(Rounding_Dir dir) {
+ return round_inverse(dir);
+}
+
+// The FPU mode is "round down".
+//
+// The result of the rounded down multiplication is thus computed directly.
+//
+// a = 0.3
+// b = 0.1
+// c_i = a * b = 0.03
+// c = c_i = 0.0
+//
+// To obtain the result of the rounded up multiplication
+// we do -(-a * b).
+//
+// a = 0.3
+// b = 0.1
+// c_i = -a * b = -0.03
+//
+// Here c_i should be forced to lose excess precision, otherwise the
+// FPU will truncate using the rounding mode in force, which is "round down".
+//
+// c_i = -c_i = 0.03
+// c = c_i = 0.0
+//
+// Wrong result: we should have obtained c = 0.1.
+
+inline void
+limit_precision(const float& v) {
+ cc_flush(v);
+}
+
+inline void
+limit_precision(const double& v) {
+ cc_flush(v);
+}
+
+inline void
+limit_precision(const long double&) {
+}
+
+template <typename Policy, typename T>
+inline Result
+classify_float(const T v, bool nan, bool inf, bool sign) {
+ Float<T> f(v);
+ if ((nan || sign) && CHECK_P(Policy::has_nan, f.u.binary.is_nan()))
+ return V_NAN;
+ if (inf) {
+ int i = CHECK_P(Policy::has_infinity, f.u.binary.is_inf());
+ if (i < 0)
+ return V_EQ_MINUS_INFINITY;
+ if (i > 0)
+ return V_EQ_PLUS_INFINITY;
+ }
+ if (sign) {
+ if (v < 0)
+ return V_LT;
+ if (v > 0)
+ return V_GT;
+ return V_EQ;
+ }
+ return V_LGE;
+}
+
+template <typename Policy, typename T>
+inline bool
+is_nan_float(const T v) {
+ Float<T> f(v);
+ return CHECK_P(Policy::has_nan, f.u.binary.is_nan());
+}
+
+template <typename Policy, typename T>
+inline int
+is_inf_float(const T v) {
+ Float<T> f(v);
+ return CHECK_P(Policy::has_infinity, f.u.binary.is_inf());
+}
+template <typename Policy, typename T>
+inline bool
+is_minf_float(const T v) {
+ return is_inf_float<Policy>(v) < 0;
+}
+
+template <typename Policy, typename T>
+inline bool
+is_pinf_float(const T v) {
+ return is_inf_float<Policy>(v) > 0;
+}
+
+
+template <typename Policy, typename T>
+inline bool
+is_int_float(const T v) {
+ return rint(v) == v;
+}
+
+template <typename Policy, typename T>
+inline Result
+assign_special_float(T& v, Result_Class c, Rounding_Dir) {
+ switch (c) {
+ case VC_MINUS_INFINITY:
+ v = -HUGE_VAL;
+ return V_EQ_MINUS_INFINITY;
+ case VC_PLUS_INFINITY:
+ v = HUGE_VAL;
+ return V_EQ_PLUS_INFINITY;
+ case VC_NAN:
+ v = PPL_NAN;
+ return V_NAN;
+ default:
+ PPL_ASSERT(false);
+ return V_NAN | V_UNREPRESENTABLE;
+ }
+}
+
+template <typename T>
+inline void
+pred_float(T& v) {
+ Float<T> f(v);
+ PPL_ASSERT(!f.u.binary.is_nan());
+ PPL_ASSERT(f.u.binary.is_inf() >= 0);
+ if (f.u.binary.is_zero() > 0) {
+ f.u.binary.negate();
+ f.u.binary.inc();
+ }
+ else if (f.u.binary.sign_bit()) {
+ f.u.binary.inc();
+ }
+ else {
+ f.u.binary.dec();
+ }
+ v = f.value();
+}
+
+template <typename T>
+inline void
+succ_float(T& v) {
+ Float<T> f(v);
+ PPL_ASSERT(!f.u.binary.is_nan());
+ PPL_ASSERT(f.u.binary.is_inf() <= 0);
+ if (f.u.binary.is_zero() < 0) {
+ f.u.binary.negate();
+ f.u.binary.inc();
+ }
+ else if (!f.u.binary.sign_bit()) {
+ f.u.binary.inc();
+ }
+ else {
+ f.u.binary.dec();
+ }
+ v = f.value();
+}
+
+template <typename Policy, typename To>
+inline Result
+round_lt_float(To& to, Rounding_Dir dir) {
+ if (round_down(dir)) {
+ pred_float(to);
+ return V_GT;
+ }
+ return V_LT;
+}
+
+template <typename Policy, typename To>
+inline Result
+round_gt_float(To& to, Rounding_Dir dir) {
+ if (round_up(dir)) {
+ succ_float(to);
+ return V_LT;
+ }
+ return V_GT;
+}
+
+
+template <typename Policy>
+inline void
+prepare_inexact(Rounding_Dir dir) {
+ if (Policy::fpu_check_inexact
+ && !round_not_needed(dir) && round_strict_relation(dir))
+ fpu_reset_inexact();
+}
+
+template <typename Policy>
+inline Result
+result_relation(Rounding_Dir dir) {
+ if (Policy::fpu_check_inexact
+ && !round_not_needed(dir) && round_strict_relation(dir)) {
+ switch (fpu_check_inexact()) {
+ case 0:
+ return V_EQ;
+ case -1:
+ goto unknown;
+ case 1:
+ break;
+ }
+ switch (round_dir(dir)) {
+ case ROUND_DOWN:
+ return V_GT;
+ case ROUND_UP:
+ return V_LT;
+ default:
+ return V_NE;
+ }
+ }
+ else {
+ unknown:
+ switch (round_dir(dir)) {
+ case ROUND_DOWN:
+ return V_GE;
+ case ROUND_UP:
+ return V_LE;
+ default:
+ return V_LGE;
+ }
+ }
+}
+
+template <typename To_Policy, typename From_Policy, typename To, typename From>
+inline Result
+assign_float_float_exact(To& to, const From from, Rounding_Dir) {
+ if (To_Policy::fpu_check_nan_result && is_nan<From_Policy>(from))
+ return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
+ to = from;
+ return V_EQ;
+}
+
+template <typename To_Policy, typename From_Policy, typename To, typename From>
+inline Result
+assign_float_float_inexact(To& to, const From from, Rounding_Dir dir) {
+ if (To_Policy::fpu_check_nan_result && is_nan<From_Policy>(from))
+ return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
+ prepare_inexact<To_Policy>(dir);
+ if (fpu_direct_rounding(dir))
+ to = from;
+ else if (fpu_inverse_rounding(dir)) {
+ From tmp = -from;
+ to = tmp;
+ limit_precision(to);
+ to = -to;
+ }
+ else {
+ fpu_rounding_control_word_type old
+ = fpu_save_rounding_direction(round_fpu_dir(dir));
+ limit_precision(from);
+ to = from;
+ limit_precision(to);
+ fpu_restore_rounding_direction(old);
+ }
+ return result_relation<To_Policy>(dir);
+}
+
+template <typename To_Policy, typename From_Policy, typename To, typename From>
+inline Result
+assign_float_float(To& to, const From from, Rounding_Dir dir) {
+ if (sizeof(From) > sizeof(To))
+ return assign_float_float_inexact<To_Policy, From_Policy>(to, from, dir);
+ else
+ return assign_float_float_exact<To_Policy, From_Policy>(to, from, dir);
+}
+
+template <typename To_Policy, typename From_Policy, typename Type>
+inline Result
+floor_float(Type& to, const Type from, Rounding_Dir) {
+ if (To_Policy::fpu_check_nan_result && is_nan<From_Policy>(from))
+ return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
+ if (fpu_direct_rounding(ROUND_DOWN))
+ to = rint(from);
+ else if (fpu_inverse_rounding(ROUND_DOWN)) {
+ to = rint(-from);
+ limit_precision(to);
+ to = -to;
+ }
+ else {
+ fpu_rounding_control_word_type old
+ = fpu_save_rounding_direction(round_fpu_dir(ROUND_DOWN));
+ limit_precision(from);
+ to = rint(from);
+ limit_precision(to);
+ fpu_restore_rounding_direction(old);
+ }
+ return V_EQ;
+}
+
+template <typename To_Policy, typename From_Policy, typename Type>
+inline Result
+ceil_float(Type& to, const Type from, Rounding_Dir) {
+ if (To_Policy::fpu_check_nan_result && is_nan<From_Policy>(from))
+ return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
+ if (fpu_direct_rounding(ROUND_UP))
+ to = rint(from);
+ else if (fpu_inverse_rounding(ROUND_UP)) {
+ to = rint(-from);
+ limit_precision(to);
+ to = -to;
+ }
+ else {
+ fpu_rounding_control_word_type old
+ = fpu_save_rounding_direction(round_fpu_dir(ROUND_UP));
+ limit_precision(from);
+ to = rint(from);
+ limit_precision(to);
+ fpu_restore_rounding_direction(old);
+ }
+ return V_EQ;
+}
+
+template <typename To_Policy, typename From_Policy, typename Type>
+inline Result
+trunc_float(Type& to, const Type from, Rounding_Dir dir) {
+ if (To_Policy::fpu_check_nan_result && is_nan<From_Policy>(from))
+ return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
+ if (from >= 0)
+ return floor<To_Policy, From_Policy>(to, from, dir);
+ else
+ return ceil<To_Policy, From_Policy>(to, from, dir);
+}
+
+template <typename To_Policy, typename From_Policy, typename Type>
+inline Result
+neg_float(Type& to, const Type from, Rounding_Dir) {
+ if (To_Policy::fpu_check_nan_result && is_nan<From_Policy>(from))
+ return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
+ to = -from;
+ return V_EQ;
+}
+
+template <typename To_Policy, typename From1_Policy, typename From2_Policy,
+ typename Type>
+inline Result
+add_float(Type& to, const Type x, const Type y, Rounding_Dir dir) {
+ if (To_Policy::check_inf_add_inf
+ && is_inf_float<From1_Policy>(x) && x == -y) {
+ return assign_nan<To_Policy>(to, V_INF_ADD_INF);
+ }
+ prepare_inexact<To_Policy>(dir);
+ if (fpu_direct_rounding(dir))
+ to = x + y;
+ else if (fpu_inverse_rounding(dir)) {
+ to = -x - y;
+ limit_precision(to);
+ to = -to;
+ }
+ else {
+ fpu_rounding_control_word_type old
+ = fpu_save_rounding_direction(round_fpu_dir(dir));
+ limit_precision(x);
+ limit_precision(y);
+ to = x + y;
+ limit_precision(to);
+ fpu_restore_rounding_direction(old);
+ }
+ if (To_Policy::fpu_check_nan_result && is_nan<To_Policy>(to))
+ return V_NAN;
+ return result_relation<To_Policy>(dir);
+}
+
+template <typename To_Policy, typename From1_Policy, typename From2_Policy,
+ typename Type>
+inline Result
+sub_float(Type& to, const Type x, const Type y, Rounding_Dir dir) {
+ if (To_Policy::check_inf_sub_inf
+ && is_inf_float<From1_Policy>(x) && x == y) {
+ return assign_nan<To_Policy>(to, V_INF_SUB_INF);
+ }
+ prepare_inexact<To_Policy>(dir);
+ if (fpu_direct_rounding(dir))
+ to = x - y;
+ else if (fpu_inverse_rounding(dir)) {
+ to = y - x;
+ limit_precision(to);
+ to = -to;
+ }
+ else {
+ fpu_rounding_control_word_type old
+ = fpu_save_rounding_direction(round_fpu_dir(dir));
+ limit_precision(x);
+ limit_precision(y);
+ to = x - y;
+ limit_precision(to);
+ fpu_restore_rounding_direction(old);
+ }
+ if (To_Policy::fpu_check_nan_result && is_nan<To_Policy>(to))
+ return V_NAN;
+ return result_relation<To_Policy>(dir);
+}
+
+template <typename To_Policy, typename From1_Policy, typename From2_Policy,
+ typename Type>
+inline Result
+mul_float(Type& to, const Type x, const Type y, Rounding_Dir dir) {
+ if (To_Policy::check_inf_mul_zero
+ && ((x == 0 && is_inf_float<From2_Policy>(y))
+ ||
+ (y == 0 && is_inf_float<From1_Policy>(x)))) {
+ return assign_nan<To_Policy>(to, V_INF_MUL_ZERO);
+ }
+ prepare_inexact<To_Policy>(dir);
+ if (fpu_direct_rounding(dir))
+ to = x * y;
+ else if (fpu_inverse_rounding(dir)) {
+ to = x * -y;
+ limit_precision(to);
+ to = -to;
+ }
+ else {
+ fpu_rounding_control_word_type old
+ = fpu_save_rounding_direction(round_fpu_dir(dir));
+ limit_precision(x);
+ limit_precision(y);
+ to = x * y;
+ limit_precision(to);
+ fpu_restore_rounding_direction(old);
+ }
+ if (To_Policy::fpu_check_nan_result && is_nan<To_Policy>(to))
+ return V_NAN;
+ return result_relation<To_Policy>(dir);
+}
+
+template <typename To_Policy, typename From1_Policy, typename From2_Policy,
+ typename Type>
+inline Result
+div_float(Type& to, const Type x, const Type y, Rounding_Dir dir) {
+ if (To_Policy::check_inf_div_inf
+ && is_inf_float<From1_Policy>(x) && is_inf_float<From2_Policy>(y)) {
+ return assign_nan<To_Policy>(to, V_INF_DIV_INF);
+ }
+ if (To_Policy::check_div_zero && y == 0) {
+ return assign_nan<To_Policy>(to, V_DIV_ZERO);
+ }
+ prepare_inexact<To_Policy>(dir);
+ if (fpu_direct_rounding(dir))
+ to = x / y;
+ else if (fpu_inverse_rounding(dir)) {
+ to = x / -y;
+ limit_precision(to);
+ to = -to;
+ }
+ else {
+ fpu_rounding_control_word_type old
+ = fpu_save_rounding_direction(round_fpu_dir(dir));
+ limit_precision(x);
+ limit_precision(y);
+ to = x / y;
+ limit_precision(to);
+ fpu_restore_rounding_direction(old);
+ }
+ if (To_Policy::fpu_check_nan_result && is_nan<To_Policy>(to))
+ return V_NAN;
+ return result_relation<To_Policy>(dir);
+}
+
+template <typename To_Policy, typename From1_Policy, typename From2_Policy,
+ typename Type>
+inline Result
+idiv_float(Type& to, const Type x, const Type y, Rounding_Dir dir) {
+ Type temp;
+ // The inexact check is useless
+ dir = round_dir(dir);
+ Result r = div<To_Policy, From1_Policy, From2_Policy>(temp, x, y, dir);
+ if (result_class(r) != VC_NORMAL) {
+ to = temp;
+ return r;
+ }
+ Result r1 = trunc<To_Policy, To_Policy>(to, temp, ROUND_NOT_NEEDED);
+ PPL_ASSERT(r1 == V_EQ);
+ if (r == V_EQ || to != temp)
+ return r1;
+ // FIXME: Prove that it's impossibile to return a strict relation
+ return dir == ROUND_UP ? V_LE : V_GE;
+}
+
+template <typename To_Policy, typename From1_Policy, typename From2_Policy,
+ typename Type>
+inline Result
+rem_float(Type& to, const Type x, const Type y, Rounding_Dir) {
+ if (To_Policy::check_inf_mod && is_inf_float<From1_Policy>(x)) {
+ return assign_nan<To_Policy>(to, V_INF_MOD);
+ }
+ if (To_Policy::check_div_zero && y == 0) {
+ return assign_nan<To_Policy>(to, V_MOD_ZERO);
+ }
+ to = std::fmod(x, y);
+ if (To_Policy::fpu_check_nan_result && is_nan<To_Policy>(to))
+ return V_NAN;
+ return V_EQ;
+}
+
+struct Float_2exp {
+ const_bool_nodef(has_nan, false);
+ const_bool_nodef(has_infinity, false);
+};
+
+template <typename To_Policy, typename From_Policy, typename Type>
+inline Result
+add_2exp_float(Type& to, const Type x, unsigned int exp, Rounding_Dir dir) {
+ if (To_Policy::fpu_check_nan_result && is_nan<From_Policy>(x))
+ return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
+ PPL_ASSERT(exp < sizeof(unsigned long long) * CHAR_BIT);
+ return
+ add<To_Policy, From_Policy, Float_2exp>(to,
+ x,
+ Type(1ULL << exp),
+ dir);
+}
+
+template <typename To_Policy, typename From_Policy, typename Type>
+inline Result
+sub_2exp_float(Type& to, const Type x, unsigned int exp, Rounding_Dir dir) {
+ if (To_Policy::fpu_check_nan_result && is_nan<From_Policy>(x))
+ return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
+ PPL_ASSERT(exp < sizeof(unsigned long long) * CHAR_BIT);
+ return
+ sub<To_Policy, From_Policy, Float_2exp>(to,
+ x,
+ Type(1ULL << exp),
+ dir);
+}
+
+template <typename To_Policy, typename From_Policy, typename Type>
+inline Result
+mul_2exp_float(Type& to, const Type x, unsigned int exp, Rounding_Dir dir) {
+ if (To_Policy::fpu_check_nan_result && is_nan<From_Policy>(x))
+ return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
+ PPL_ASSERT(exp < sizeof(unsigned long long) * CHAR_BIT);
+ return
+ mul<To_Policy, From_Policy, Float_2exp>(to,
+ x,
+ Type(1ULL << exp),
+ dir);
+}
+
+template <typename To_Policy, typename From_Policy, typename Type>
+inline Result
+div_2exp_float(Type& to, const Type x, unsigned int exp, Rounding_Dir dir) {
+ if (To_Policy::fpu_check_nan_result && is_nan<From_Policy>(x))
+ return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
+ PPL_ASSERT(exp < sizeof(unsigned long long) * CHAR_BIT);
+ return
+ div<To_Policy, From_Policy, Float_2exp>(to,
+ x,
+ Type(1ULL << exp),
+ dir);
+}
+
+template <typename To_Policy, typename From_Policy, typename Type>
+inline Result
+smod_2exp_float(Type& to, const Type x, unsigned int exp, Rounding_Dir dir) {
+ if (To_Policy::fpu_check_nan_result && is_nan<From_Policy>(x))
+ return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
+ if (To_Policy::check_inf_mod && is_inf_float<From_Policy>(x)) {
+ return assign_nan<To_Policy>(to, V_INF_MOD);
+ }
+ PPL_ASSERT(exp < sizeof(unsigned long long) * CHAR_BIT);
+ Type m = 1ULL << exp;
+ rem_float<To_Policy, From_Policy, Float_2exp>(to, x, m, ROUND_IGNORE);
+ Type m2 = m / 2;
+ if (to < -m2)
+ return add_float<To_Policy, From_Policy, Float_2exp>(to, to, m, dir);
+ else if (to >= m2)
+ return sub_float<To_Policy, From_Policy, Float_2exp>(to, to, m, dir);
+ return V_EQ;
+}
+
+template <typename To_Policy, typename From_Policy, typename Type>
+inline Result
+umod_2exp_float(Type& to, const Type x, unsigned int exp, Rounding_Dir dir) {
+ if (To_Policy::fpu_check_nan_result && is_nan<From_Policy>(x))
+ return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
+ if (To_Policy::check_inf_mod && is_inf_float<From_Policy>(x)) {
+ return assign_nan<To_Policy>(to, V_INF_MOD);
+ }
+ PPL_ASSERT(exp < sizeof(unsigned long long) * CHAR_BIT);
+ Type m = 1ULL << exp;
+ rem_float<To_Policy, From_Policy, Float_2exp>(to, x, m, ROUND_IGNORE);
+ if (to < 0)
+ return add_float<To_Policy, From_Policy, Float_2exp>(to, to, m, dir);
+ return V_EQ;
+}
+
+template <typename To_Policy, typename From_Policy, typename Type>
+inline Result
+abs_float(Type& to, const Type from, Rounding_Dir) {
+ if (To_Policy::fpu_check_nan_result && is_nan<From_Policy>(from))
+ return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
+ to = std::abs(from);
+ return V_EQ;
+}
+
+template <typename To_Policy, typename From_Policy, typename Type>
+inline Result
+sqrt_float(Type& to, const Type from, Rounding_Dir dir) {
+ if (To_Policy::fpu_check_nan_result && is_nan<From_Policy>(from))
+ return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
+ if (To_Policy::check_sqrt_neg && from < 0) {
+ return assign_nan<To_Policy>(to, V_SQRT_NEG);
+ }
+ prepare_inexact<To_Policy>(dir);
+ if (fpu_direct_rounding(dir))
+ to = std::sqrt(from);
+ else {
+ fpu_rounding_control_word_type old
+ = fpu_save_rounding_direction(round_fpu_dir(dir));
+ limit_precision(from);
+ to = std::sqrt(from);
+ limit_precision(to);
+ fpu_restore_rounding_direction(old);
+ }
+ return result_relation<To_Policy>(dir);
+}
+
+template <typename Policy, typename Type>
+inline Result_Relation
+sgn_float(const Type x) {
+ if (x > 0)
+ return VR_GT;
+ if (x < 0)
+ return VR_LT;
+ if (x == 0)
+ return VR_EQ;
+ return VR_EMPTY;
+}
+
+template <typename Policy1, typename Policy2, typename Type>
+inline Result_Relation
+cmp_float(const Type x, const Type y) {
+ if (x > y)
+ return VR_GT;
+ if (x < y)
+ return VR_LT;
+ if (x == y)
+ return VR_EQ;
+ return VR_EMPTY;
+}
+
+template <typename To_Policy, typename From_Policy, typename To, typename From>
+inline Result
+assign_float_int_inexact(To& to, const From from, Rounding_Dir dir) {
+ prepare_inexact<To_Policy>(dir);
+ if (fpu_direct_rounding(dir))
+ to = from;
+ else {
+ fpu_rounding_control_word_type old
+ = fpu_save_rounding_direction(round_fpu_dir(dir));
+ to = from;
+ limit_precision(to);
+ fpu_restore_rounding_direction(old);
+ }
+ return result_relation<To_Policy>(dir);
+}
+
+template <typename To_Policy, typename From_Policy, typename To, typename From>
+inline Result
+assign_float_int(To& to, const From from, Rounding_Dir dir) {
+ if (sizeof(From) * CHAR_BIT > Float<To>::Binary::MANTISSA_BITS)
+ return assign_float_int_inexact<To_Policy, From_Policy>(to, from, dir);
+ else
+ return assign_exact<To_Policy, From_Policy>(to, from, dir);
+}
+
+template <typename Policy, typename T>
+inline Result
+set_neg_overflow_float(T& to, Rounding_Dir dir) {
+ switch (round_dir(dir)) {
+ case ROUND_UP:
+ {
+ Float<T> f;
+ f.u.binary.set_max(true);
+ to = f.value();
+ return V_LT_INF;
+ }
+ default:
+ to = -HUGE_VAL;
+ return V_GT_MINUS_INFINITY;
+ }
+}
+
+template <typename Policy, typename T>
+inline Result
+set_pos_overflow_float(T& to, Rounding_Dir dir) {
+ switch (round_dir(dir)) {
+ case ROUND_DOWN:
+ {
+ Float<T> f;
+ f.u.binary.set_max(false);
+ to = f.value();
+ return V_GT_SUP;
+ }
+ default:
+ to = HUGE_VAL;
+ return V_LT_PLUS_INFINITY;
+ }
+}
+
+template <typename To_Policy, typename From_Policy, typename T>
+inline Result
+assign_float_mpz(T& to, const mpz_class& _from, Rounding_Dir dir)
+{
+ mpz_srcptr from = _from.get_mpz_t();
+ int sign = mpz_sgn(from);
+ if (sign == 0) {
+ to = 0;
+ return V_EQ;
+ }
+ size_t exponent = mpz_sizeinbase(from, 2) - 1;
+ if (exponent > size_t(Float<T>::Binary::EXPONENT_MAX)) {
+ if (sign < 0)
+ return set_neg_overflow_float<To_Policy>(to, dir);
+ else
+ return set_pos_overflow_float<To_Policy>(to, dir);
+ }
+ unsigned long zeroes = mpn_scan1(from->_mp_d, 0);
+ size_t meaningful_bits = exponent - zeroes;
+ mpz_t mantissa;
+ mpz_init(mantissa);
+ if (exponent > Float<T>::Binary::MANTISSA_BITS)
+ mpz_tdiv_q_2exp(mantissa,
+ from,
+ exponent - Float<T>::Binary::MANTISSA_BITS);
+ else
+ mpz_mul_2exp(mantissa, from, Float<T>::Binary::MANTISSA_BITS - exponent);
+ Float<T> f;
+ f.u.binary.build(sign < 0, mantissa, exponent);
+ mpz_clear(mantissa);
+ to = f.value();
+ if (meaningful_bits > Float<T>::Binary::MANTISSA_BITS) {
+ if (sign < 0)
+ return round_lt_float<To_Policy>(to, dir);
+ else
+ return round_gt_float<To_Policy>(to, dir);
+ }
+ return V_EQ;
+}
+
+template <typename To_Policy, typename From_Policy, typename T>
+inline Result
+assign_float_mpq(T& to, const mpq_class& from, Rounding_Dir dir)
+{
+ const mpz_class& _num = from.get_num();
+ const mpz_class& _den = from.get_den();
+ if (_den == 1)
+ return assign_float_mpz<To_Policy, From_Policy>(to, _num, dir);
+ mpz_srcptr num = _num.get_mpz_t();
+ mpz_srcptr den = _den.get_mpz_t();
+ int sign = mpz_sgn(num);
+ signed long exponent = mpz_sizeinbase(num, 2) - mpz_sizeinbase(den, 2);
+ if (exponent < Float<T>::Binary::EXPONENT_MIN_DENORM) {
+ to = 0;
+ inexact:
+ if (sign < 0)
+ return round_lt_float<To_Policy>(to, dir);
+ else
+ return round_gt_float<To_Policy>(to, dir);
+ }
+ if (exponent > int(Float<T>::Binary::EXPONENT_MAX + 1)) {
+ overflow:
+ if (sign < 0)
+ return set_neg_overflow_float<To_Policy>(to, dir);
+ else
+ return set_pos_overflow_float<To_Policy>(to, dir);
+ }
+ unsigned int needed_bits = Float<T>::Binary::MANTISSA_BITS + 1;
+ if (exponent < Float<T>::Binary::EXPONENT_MIN)
+ needed_bits -= Float<T>::Binary::EXPONENT_MIN - exponent;
+ mpz_t mantissa;
+ mpz_init(mantissa);
+ signed long shift = needed_bits - exponent;
+ if (shift > 0) {
+ mpz_mul_2exp(mantissa, num, shift);
+ num = mantissa;
+ }
+ else if (shift < 0) {
+ mpz_mul_2exp(mantissa, den, -shift);
+ den = mantissa;
+ }
+ mpz_t r;
+ mpz_init(r);
+ mpz_tdiv_qr(mantissa, r, num, den);
+ size_t bits = mpz_sizeinbase(mantissa, 2);
+ bool inexact = (mpz_sgn(r) != 0);
+ mpz_clear(r);
+ if (bits == needed_bits + 1) {
+ inexact = (inexact || mpz_odd_p(mantissa));
+ mpz_tdiv_q_2exp(mantissa, mantissa, 1);
+ }
+ else
+ --exponent;
+ if (exponent > int(Float<T>::Binary::EXPONENT_MAX)) {
+ mpz_clear(mantissa);
+ goto overflow;
+ }
+ else if (exponent < Float<T>::Binary::EXPONENT_MIN - 1) {
+ // Denormalized.
+ exponent = Float<T>::Binary::EXPONENT_MIN - 1;
+ }
+ Float<T> f;
+ f.u.binary.build(sign < 0, mantissa, exponent);
+ mpz_clear(mantissa);
+ to = f.value();
+ if (inexact)
+ goto inexact;
+ return V_EQ;
+}
+
+template <typename To_Policy, typename From1_Policy, typename From2_Policy,
+ typename Type>
+inline Result
+add_mul_float(Type& to, const Type x, const Type y, Rounding_Dir dir) {
+ if (To_Policy::check_inf_mul_zero
+ && ((x == 0 && is_inf_float<From2_Policy>(y))
+ ||
+ (y == 0 && is_inf_float<From1_Policy>(x)))) {
+ return assign_nan<To_Policy>(to, V_INF_MUL_ZERO);
+ }
+ // FIXME: missing check_inf_add_inf
+ prepare_inexact<To_Policy>(dir);
+ if (fpu_direct_rounding(dir))
+ to = fma(x, y, to);
+ else if (fpu_inverse_rounding(dir)) {
+ to = fma(-x, y, -to);
+ limit_precision(to);
+ to = -to;
+ }
+ else {
+ fpu_rounding_control_word_type old
+ = fpu_save_rounding_direction(round_fpu_dir(dir));
+ limit_precision(x);
+ limit_precision(y);
+ limit_precision(to);
+ to = fma(x, y, to);
+ limit_precision(to);
+ fpu_restore_rounding_direction(old);
+ }
+ if (To_Policy::fpu_check_nan_result && is_nan<To_Policy>(to))
+ return V_NAN;
+ return result_relation<To_Policy>(dir);
+}
+
+template <typename To_Policy, typename From1_Policy, typename From2_Policy, typename Type>
+inline Result
+sub_mul_float(Type& to, const Type x, const Type y, Rounding_Dir dir) {
+ if (To_Policy::check_inf_mul_zero
+ && ((x == 0 && is_inf_float<From2_Policy>(y))
+ ||
+ (y == 0 && is_inf_float<From1_Policy>(x)))) {
+ return assign_nan<To_Policy>(to, V_INF_MUL_ZERO);
+ }
+ // FIXME: missing check_inf_add_inf
+ prepare_inexact<To_Policy>(dir);
+ if (fpu_direct_rounding(dir))
+ to = fma(x, -y, to);
+ else if (fpu_inverse_rounding(dir)) {
+ to = fma(x, y, -to);
+ limit_precision(to);
+ to = -to;
+ }
+ else {
+ fpu_rounding_control_word_type old
+ = fpu_save_rounding_direction(round_fpu_dir(dir));
+ limit_precision(x);
+ limit_precision(y);
+ limit_precision(to);
+ to = fma(x, -y, to);
+ limit_precision(to);
+ fpu_restore_rounding_direction(old);
+ }
+ if (To_Policy::fpu_check_nan_result && is_nan<To_Policy>(to))
+ return V_NAN;
+ return result_relation<To_Policy>(dir);
+}
+
+template <typename Policy, typename Type>
+inline Result
+output_float(std::ostream& os, const Type from, const Numeric_Format&,
+ Rounding_Dir) {
+ if (from == 0)
+ os << "0";
+ else if (is_minf<Policy>(from))
+ os << "-inf";
+ else if (is_pinf<Policy>(from))
+ os << "+inf";
+ else if (is_nan<Policy>(from))
+ os << "nan";
+ else {
+ int old_precision = os.precision(10000);
+ // FIXME: here correctness depends on the behavior of the standard
+ // output operator which, in turn, may depend on the behavior
+ // of printf(). The C99 standard, 7.19.16.1#13, does not give
+ // enough guarantees. We could not find something similar
+ // in the C++ standard, so there is a concrete danger here.
+ os << from;
+ os.precision(old_precision);
+ }
+ return V_EQ;
+}
+
+#if PPL_SUPPORTED_FLOAT
+PPL_SPECIALIZE_ASSIGN(assign_float_float_exact, float, float)
+#if PPL_SUPPORTED_DOUBLE
+PPL_SPECIALIZE_ASSIGN(assign_float_float, float, double)
+PPL_SPECIALIZE_ASSIGN(assign_float_float_exact, double, float)
+#endif
+#if PPL_SUPPORTED_LONG_DOUBLE
+PPL_SPECIALIZE_ASSIGN(assign_float_float, float, long double)
+PPL_SPECIALIZE_ASSIGN(assign_float_float_exact, long double, float)
+#endif
+#endif
+
+#if PPL_SUPPORTED_DOUBLE
+PPL_SPECIALIZE_ASSIGN(assign_float_float_exact, double, double)
+#if PPL_SUPPORTED_LONG_DOUBLE
+PPL_SPECIALIZE_ASSIGN(assign_float_float, double, long double)
+PPL_SPECIALIZE_ASSIGN(assign_float_float_exact, long double, double)
+#endif
+#endif
+
+#if PPL_SUPPORTED_LONG_DOUBLE
+PPL_SPECIALIZE_ASSIGN(assign_float_float_exact, long double, long double)
+#endif
+
+#if PPL_SUPPORTED_FLOAT
+PPL_SPECIALIZE_CLASSIFY(classify_float, float)
+PPL_SPECIALIZE_IS_NAN(is_nan_float, float)
+PPL_SPECIALIZE_IS_MINF(is_minf_float, float)
+PPL_SPECIALIZE_IS_PINF(is_pinf_float, float)
+PPL_SPECIALIZE_ASSIGN_SPECIAL(assign_special_float, float)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, float, char)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, float, signed char)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, float, signed short)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, float, signed int)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, float, signed long)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, float, signed long long)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, float, unsigned char)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, float, unsigned short)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, float, unsigned int)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, float, unsigned long)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, float, unsigned long long)
+PPL_SPECIALIZE_ASSIGN(assign_float_mpz, float, mpz_class)
+PPL_SPECIALIZE_ASSIGN(assign_float_mpq, float, mpq_class)
+PPL_SPECIALIZE_COPY(copy_generic, float)
+PPL_SPECIALIZE_IS_INT(is_int_float, float)
+PPL_SPECIALIZE_FLOOR(floor_float, float, float)
+PPL_SPECIALIZE_CEIL(ceil_float, float, float)
+PPL_SPECIALIZE_TRUNC(trunc_float, float, float)
+PPL_SPECIALIZE_NEG(neg_float, float, float)
+PPL_SPECIALIZE_ABS(abs_float, float, float)
+PPL_SPECIALIZE_ADD(add_float, float, float, float)
+PPL_SPECIALIZE_SUB(sub_float, float, float, float)
+PPL_SPECIALIZE_MUL(mul_float, float, float, float)
+PPL_SPECIALIZE_DIV(div_float, float, float, float)
+PPL_SPECIALIZE_REM(rem_float, float, float, float)
+PPL_SPECIALIZE_ADD_2EXP(add_2exp_float, float, float)
+PPL_SPECIALIZE_SUB_2EXP(sub_2exp_float, float, float)
+PPL_SPECIALIZE_MUL_2EXP(mul_2exp_float, float, float)
+PPL_SPECIALIZE_DIV_2EXP(div_2exp_float, float, float)
+PPL_SPECIALIZE_SMOD_2EXP(smod_2exp_float, float, float)
+PPL_SPECIALIZE_UMOD_2EXP(umod_2exp_float, float, float)
+PPL_SPECIALIZE_SQRT(sqrt_float, float, float)
+PPL_SPECIALIZE_GCD(gcd_exact, float, float, float)
+PPL_SPECIALIZE_GCDEXT(gcdext_exact, float, float, float, float, float)
+PPL_SPECIALIZE_LCM(lcm_gcd_exact, float, float, float)
+PPL_SPECIALIZE_SGN(sgn_float, float)
+PPL_SPECIALIZE_CMP(cmp_float, float, float)
+PPL_SPECIALIZE_ADD_MUL(add_mul_float, float, float, float)
+PPL_SPECIALIZE_SUB_MUL(sub_mul_float, float, float, float)
+PPL_SPECIALIZE_INPUT(input_generic, float)
+PPL_SPECIALIZE_OUTPUT(output_float, float)
+#endif
+
+#if PPL_SUPPORTED_DOUBLE
+PPL_SPECIALIZE_CLASSIFY(classify_float, double)
+PPL_SPECIALIZE_IS_NAN(is_nan_float, double)
+PPL_SPECIALIZE_IS_MINF(is_minf_float, double)
+PPL_SPECIALIZE_IS_PINF(is_pinf_float, double)
+PPL_SPECIALIZE_ASSIGN_SPECIAL(assign_special_float, double)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, double, char)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, double, signed char)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, double, signed short)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, double, signed int)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, double, signed long)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, double, signed long long)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, double, unsigned char)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, double, unsigned short)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, double, unsigned int)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, double, unsigned long)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, double, unsigned long long)
+PPL_SPECIALIZE_ASSIGN(assign_float_mpz, double, mpz_class)
+PPL_SPECIALIZE_ASSIGN(assign_float_mpq, double, mpq_class)
+PPL_SPECIALIZE_COPY(copy_generic, double)
+PPL_SPECIALIZE_IS_INT(is_int_float, double)
+PPL_SPECIALIZE_FLOOR(floor_float, double, double)
+PPL_SPECIALIZE_CEIL(ceil_float, double, double)
+PPL_SPECIALIZE_TRUNC(trunc_float, double, double)
+PPL_SPECIALIZE_NEG(neg_float, double, double)
+PPL_SPECIALIZE_ABS(abs_float, double, double)
+PPL_SPECIALIZE_ADD(add_float, double, double, double)
+PPL_SPECIALIZE_SUB(sub_float, double, double, double)
+PPL_SPECIALIZE_MUL(mul_float, double, double, double)
+PPL_SPECIALIZE_DIV(div_float, double, double, double)
+PPL_SPECIALIZE_REM(rem_float, double, double, double)
+PPL_SPECIALIZE_ADD_2EXP(add_2exp_float, double, double)
+PPL_SPECIALIZE_SUB_2EXP(sub_2exp_float, double, double)
+PPL_SPECIALIZE_MUL_2EXP(mul_2exp_float, double, double)
+PPL_SPECIALIZE_DIV_2EXP(div_2exp_float, double, double)
+PPL_SPECIALIZE_SMOD_2EXP(smod_2exp_float, double, double)
+PPL_SPECIALIZE_UMOD_2EXP(umod_2exp_float, double, double)
+PPL_SPECIALIZE_SQRT(sqrt_float, double, double)
+PPL_SPECIALIZE_GCD(gcd_exact, double, double, double)
+PPL_SPECIALIZE_GCDEXT(gcdext_exact, double, double, double, double, double)
+PPL_SPECIALIZE_LCM(lcm_gcd_exact, double, double, double)
+PPL_SPECIALIZE_SGN(sgn_float, double)
+PPL_SPECIALIZE_CMP(cmp_float, double, double)
+PPL_SPECIALIZE_ADD_MUL(add_mul_float, double, double, double)
+PPL_SPECIALIZE_SUB_MUL(sub_mul_float, double, double, double)
+PPL_SPECIALIZE_INPUT(input_generic, double)
+PPL_SPECIALIZE_OUTPUT(output_float, double)
+#endif
+
+#if PPL_SUPPORTED_LONG_DOUBLE
+PPL_SPECIALIZE_CLASSIFY(classify_float, long double)
+PPL_SPECIALIZE_IS_NAN(is_nan_float, long double)
+PPL_SPECIALIZE_IS_MINF(is_minf_float, long double)
+PPL_SPECIALIZE_IS_PINF(is_pinf_float, long double)
+PPL_SPECIALIZE_ASSIGN_SPECIAL(assign_special_float, long double)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, char)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, signed char)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, signed short)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, signed int)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, signed long)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, signed long long)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, unsigned char)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, unsigned short)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, unsigned int)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, unsigned long)
+PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, unsigned long long)
+PPL_SPECIALIZE_ASSIGN(assign_float_mpz, long double, mpz_class)
+PPL_SPECIALIZE_ASSIGN(assign_float_mpq, long double, mpq_class)
+PPL_SPECIALIZE_COPY(copy_generic, long double)
+PPL_SPECIALIZE_IS_INT(is_int_float, long double)
+PPL_SPECIALIZE_FLOOR(floor_float, long double, long double)
+PPL_SPECIALIZE_CEIL(ceil_float, long double, long double)
+PPL_SPECIALIZE_TRUNC(trunc_float, long double, long double)
+PPL_SPECIALIZE_NEG(neg_float, long double, long double)
+PPL_SPECIALIZE_ABS(abs_float, long double, long double)
+PPL_SPECIALIZE_ADD(add_float, long double, long double, long double)
+PPL_SPECIALIZE_SUB(sub_float, long double, long double, long double)
+PPL_SPECIALIZE_MUL(mul_float, long double, long double, long double)
+PPL_SPECIALIZE_DIV(div_float, long double, long double, long double)
+PPL_SPECIALIZE_REM(rem_float, long double, long double, long double)
+PPL_SPECIALIZE_ADD_2EXP(add_2exp_float, long double, long double)
+PPL_SPECIALIZE_SUB_2EXP(sub_2exp_float, long double, long double)
+PPL_SPECIALIZE_MUL_2EXP(mul_2exp_float, long double, long double)
+PPL_SPECIALIZE_DIV_2EXP(div_2exp_float, long double, long double)
+PPL_SPECIALIZE_SMOD_2EXP(smod_2exp_float, long double, long double)
+PPL_SPECIALIZE_UMOD_2EXP(umod_2exp_float, long double, long double)
+PPL_SPECIALIZE_SQRT(sqrt_float, long double, long double)
+PPL_SPECIALIZE_GCD(gcd_exact, long double, long double, long double)
+PPL_SPECIALIZE_GCDEXT(gcdext_exact, long double, long double, long double,
+ long double, long double)
+PPL_SPECIALIZE_LCM(lcm_gcd_exact, long double, long double, long double)
+PPL_SPECIALIZE_SGN(sgn_float, long double)
+PPL_SPECIALIZE_CMP(cmp_float, long double, long double)
+PPL_SPECIALIZE_ADD_MUL(add_mul_float, long double, long double, long double)
+PPL_SPECIALIZE_SUB_MUL(sub_mul_float, long double, long double, long double)
+PPL_SPECIALIZE_INPUT(input_generic, long double)
+PPL_SPECIALIZE_OUTPUT(output_float, long double)
+#endif
+
+} // namespace Checked
+
+} // namespace Parma_Polyhedra_Library
+
+#endif // !defined(PPL_checked_int_inlines_hh)