summaryrefslogtreecommitdiff
path: root/boost/geometry/util/math.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/geometry/util/math.hpp')
-rw-r--r--boost/geometry/util/math.hpp171
1 files changed, 153 insertions, 18 deletions
diff --git a/boost/geometry/util/math.hpp b/boost/geometry/util/math.hpp
index 4042f4e4cd..d84b11f480 100644
--- a/boost/geometry/util/math.hpp
+++ b/boost/geometry/util/math.hpp
@@ -26,12 +26,11 @@
#include <boost/core/ignore_unused.hpp>
#include <boost/math/constants/constants.hpp>
-#ifdef BOOST_GEOMETRY_SQRT_CHECK_FINITENESS
#include <boost/math/special_functions/fpclassify.hpp>
-#endif // BOOST_GEOMETRY_SQRT_CHECK_FINITENESS
-#include <boost/math/special_functions/round.hpp>
+//#include <boost/math/special_functions/round.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/type_traits/is_fundamental.hpp>
+#include <boost/type_traits/is_integral.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
@@ -86,6 +85,9 @@ struct abs<T, true>
{
static inline T apply(T const& value)
{
+ using ::fabs;
+ using std::fabs; // for long double
+
return fabs(value);
}
};
@@ -161,7 +163,17 @@ struct equals<Type, true>
return true;
}
- return abs<Type>::apply(a - b) <= std::numeric_limits<Type>::epsilon() * policy.apply(a, b);
+ if (boost::math::isfinite(a) && boost::math::isfinite(b))
+ {
+ // If a is INF and b is e.g. 0, the expression below returns true
+ // but the values are obviously not equal, hence the condition
+ return abs<Type>::apply(a - b)
+ <= std::numeric_limits<Type>::epsilon() * policy.apply(a, b);
+ }
+ else
+ {
+ return a == b;
+ }
}
};
@@ -295,8 +307,66 @@ struct square_root<T, true>
};
+
+template
+<
+ typename T,
+ bool IsFundemantal = boost::is_fundamental<T>::value /* false */
+>
+struct modulo
+{
+ typedef T return_type;
+
+ static inline T apply(T const& value1, T const& value2)
+ {
+ // for non-fundamental number types assume that a free
+ // function mod() is defined either:
+ // 1) at T's scope, or
+ // 2) at global scope
+ return mod(value1, value2);
+ }
+};
+
+template
+<
+ typename Fundamental,
+ bool IsIntegral = boost::is_integral<Fundamental>::value
+>
+struct modulo_for_fundamental
+{
+ typedef Fundamental return_type;
+
+ static inline Fundamental apply(Fundamental const& value1,
+ Fundamental const& value2)
+ {
+ return value1 % value2;
+ }
+};
+
+// specialization for floating-point numbers
+template <typename Fundamental>
+struct modulo_for_fundamental<Fundamental, false>
+{
+ typedef Fundamental return_type;
+
+ static inline Fundamental apply(Fundamental const& value1,
+ Fundamental const& value2)
+ {
+ return std::fmod(value1, value2);
+ }
+};
+
+// specialization for fundamental number type
+template <typename Fundamental>
+struct modulo<Fundamental, true>
+ : modulo_for_fundamental<Fundamental>
+{};
+
+
+
/*!
-\brief Short construct to enable partial specialization for PI, currently not possible in Math.
+\brief Short constructs to enable partial specialization for PI, 2*PI
+ and PI/2, currently not possible in Math.
*/
template <typename T>
struct define_pi
@@ -309,6 +379,26 @@ struct define_pi
};
template <typename T>
+struct define_two_pi
+{
+ static inline T apply()
+ {
+ // Default calls Boost.Math
+ return boost::math::constants::two_pi<T>();
+ }
+};
+
+template <typename T>
+struct define_half_pi
+{
+ static inline T apply()
+ {
+ // Default calls Boost.Math
+ return boost::math::constants::half_pi<T>();
+ }
+};
+
+template <typename T>
struct relaxed_epsilon
{
static inline T apply(const T& factor)
@@ -321,7 +411,7 @@ struct relaxed_epsilon
template <typename Result, typename Source,
bool ResultIsInteger = std::numeric_limits<Result>::is_integer,
bool SourceIsInteger = std::numeric_limits<Source>::is_integer>
-struct round
+struct rounding_cast
{
static inline Result apply(Source const& v)
{
@@ -329,16 +419,25 @@ struct round
}
};
+// TtoT
+template <typename Source, bool ResultIsInteger, bool SourceIsInteger>
+struct rounding_cast<Source, Source, ResultIsInteger, SourceIsInteger>
+{
+ static inline Source apply(Source const& v)
+ {
+ return v;
+ }
+};
+
// FtoI
template <typename Result, typename Source>
-struct round<Result, Source, true, false>
+struct rounding_cast<Result, Source, true, false>
{
static inline Result apply(Source const& v)
{
- namespace bmp = boost::math::policies;
- // ignore rounding errors for backward compatibility
- typedef bmp::policy< bmp::rounding_error<bmp::ignore_error> > policy;
- return boost::numeric_cast<Result>(boost::math::round(v, policy()));
+ return boost::numeric_cast<Result>(v < Source(0) ?
+ v - Source(0.5) :
+ v + Source(0.5));
}
};
@@ -350,6 +449,12 @@ template <typename T>
inline T pi() { return detail::define_pi<T>::apply(); }
template <typename T>
+inline T two_pi() { return detail::define_two_pi<T>::apply(); }
+
+template <typename T>
+inline T half_pi() { return detail::define_half_pi<T>::apply(); }
+
+template <typename T>
inline T relaxed_epsilon(T const& factor)
{
return detail::relaxed_epsilon<T>::apply(factor);
@@ -408,9 +513,20 @@ inline bool larger(T1 const& a, T2 const& b)
}
+template <typename T>
+inline T d2r()
+{
+ static T const conversion_coefficient = geometry::math::pi<T>() / T(180.0);
+ return conversion_coefficient;
+}
+
+template <typename T>
+inline T r2d()
+{
+ static T const conversion_coefficient = T(180.0) / geometry::math::pi<T>();
+ return conversion_coefficient;
+}
-double const d2r = geometry::math::pi<double>() / 180.0;
-double const r2d = 1.0 / d2r;
/*!
\brief Calculates the haversine of an angle
@@ -455,6 +571,24 @@ sqrt(T const& value)
}
/*!
+\brief Short utility to return the modulo of two values
+\ingroup utility
+\param value1 First value
+\param value2 Second value
+\return The result of the modulo operation on the (ordered) pair
+(value1, value2)
+*/
+template <typename T>
+inline typename detail::modulo<T>::return_type
+mod(T const& value1, T const& value2)
+{
+ return detail::modulo
+ <
+ T, boost::is_fundamental<T>::value
+ >::apply(value1, value2);
+}
+
+/*!
\brief Short utility to workaround gcc/clang problem that abs is converting to integer
and that older versions of MSVC does not support abs of long long...
\ingroup utility
@@ -470,23 +604,24 @@ inline T abs(T const& value)
\ingroup utility
*/
template <typename T>
-static inline int sign(T const& value)
+inline int sign(T const& value)
{
T const zero = T();
return value > zero ? 1 : value < zero ? -1 : 0;
}
/*!
-\brief Short utility to calculate the rounded value of a number.
+\brief Short utility to cast a value possibly rounding it to the nearest
+ integral value.
\ingroup utility
\note If the source T is NOT an integral type and Result is an integral type
the value is rounded towards the closest integral value. Otherwise it's
- casted.
+ casted without rounding.
*/
template <typename Result, typename T>
-inline Result round(T const& v)
+inline Result rounding_cast(T const& v)
{
- return detail::round<Result, T>::apply(v);
+ return detail::rounding_cast<Result, T>::apply(v);
}
} // namespace math