From 434aa8d3c54e1dae529fcbf6d99fc1490aebbcaf Mon Sep 17 00:00:00 2001 From: bolero-MURAKAMI Date: Sun, 10 Feb 2013 11:54:54 +0900 Subject: [PATCH] fix math: rounding function,etc... --- sprout/functional/bind/bind.hpp | 1 + sprout/functional/hash/detail/hash_float.hpp | 12 +- sprout/math/detail/config.hpp | 7 + sprout/math/float2_exponent.hpp | 38 +++++ sprout/math/float2_sig_exp.hpp | 46 ++++++ sprout/math/float2_significand.hpp | 39 +++++ sprout/math/float_frac_int.hpp | 45 ++++++ sprout/math/float_fractional_part.hpp | 38 +++++ sprout/math/float_integer_part.hpp | 38 +++++ .../{float_pair.hpp => float_sig_exp.hpp} | 20 +-- ...oat_mantissa.hpp => float_significand.hpp} | 16 +- sprout/math/floating_point.hpp | 12 +- sprout/math/iceil.hpp | 75 +++++++++ sprout/math/ifloor.hpp | 75 +++++++++ sprout/math/ilogb2.hpp | 71 +++++++++ sprout/math/iround.hpp | 83 ++++++++++ sprout/math/itrunc.hpp | 66 ++++++++ sprout/math/llround.hpp | 23 +-- sprout/math/logb.hpp | 12 +- sprout/math/logb2.hpp | 142 ++++++++++++++++++ sprout/math/lround.hpp | 23 +-- sprout/math/nearest.hpp | 4 + 22 files changed, 812 insertions(+), 74 deletions(-) create mode 100644 sprout/math/float2_exponent.hpp create mode 100644 sprout/math/float2_sig_exp.hpp create mode 100644 sprout/math/float2_significand.hpp create mode 100644 sprout/math/float_frac_int.hpp create mode 100644 sprout/math/float_fractional_part.hpp create mode 100644 sprout/math/float_integer_part.hpp rename sprout/math/{float_pair.hpp => float_sig_exp.hpp} (65%) rename sprout/math/{float_mantissa.hpp => float_significand.hpp} (66%) create mode 100644 sprout/math/iceil.hpp create mode 100644 sprout/math/ifloor.hpp create mode 100644 sprout/math/ilogb2.hpp create mode 100644 sprout/math/iround.hpp create mode 100644 sprout/math/itrunc.hpp create mode 100644 sprout/math/logb2.hpp diff --git a/sprout/functional/bind/bind.hpp b/sprout/functional/bind/bind.hpp index 94b552b4..54230baa 100644 --- a/sprout/functional/bind/bind.hpp +++ b/sprout/functional/bind/bind.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/sprout/functional/hash/detail/hash_float.hpp b/sprout/functional/hash/detail/hash_float.hpp index 1ea49585..2f62d2e9 100644 --- a/sprout/functional/hash/detail/hash_float.hpp +++ b/sprout/functional/hash/detail/hash_float.hpp @@ -6,8 +6,8 @@ #include #include #include -#include -#include +#include +#include #include namespace sprout { @@ -21,7 +21,7 @@ namespace sprout { inline SPROUT_CONSTEXPR std::size_t float_hash_value_impl_4(T v, int exp, std::size_t seed, std::size_t length, std::size_t i = 0) { return i != length ? sprout::detail::float_hash_value_impl_4( - sprout::math::scalbn(v - static_cast(static_cast(v)), std::numeric_limits::digits), + sprout::math::ldexp(v - static_cast(static_cast(v)), std::numeric_limits::digits), exp, sprout::detail::hash_float_combine(seed, static_cast(v)), length, i + 1 ) @@ -32,7 +32,7 @@ namespace sprout { inline SPROUT_CONSTEXPR std::size_t float_hash_value_impl_3(T v, int exp) { return sprout::detail::float_hash_value_impl_4( - sprout::math::scalbn(v - static_cast(static_cast(v)), std::numeric_limits::digits), + sprout::math::ldexp(v - static_cast(static_cast(v)), std::numeric_limits::digits), exp, static_cast(v), (std::numeric_limits::digits * sprout::detail::static_log2::radix>::value + std::numeric_limits::digits - 1) / std::numeric_limits::digits @@ -41,7 +41,7 @@ namespace sprout { template inline SPROUT_CONSTEXPR std::size_t float_hash_value_impl_2(T v, int exp) { - return sprout::detail::float_hash_value_impl_3(sprout::math::scalbn(v, std::numeric_limits::digits), exp); + return sprout::detail::float_hash_value_impl_3(sprout::math::ldexp(v, std::numeric_limits::digits), exp); } template inline SPROUT_CONSTEXPR std::size_t @@ -55,7 +55,7 @@ namespace sprout { template inline SPROUT_CONSTEXPR std::size_t float_hash_value_impl(T v) { - return sprout::detail::float_hash_value_impl_1(sprout::math::float_pair(v)); + return sprout::detail::float_hash_value_impl_1(sprout::math::float2_sig_exp(v)); } template diff --git a/sprout/math/detail/config.hpp b/sprout/math/detail/config.hpp index ad6be8c1..e5363435 100644 --- a/sprout/math/detail/config.hpp +++ b/sprout/math/detail/config.hpp @@ -1,6 +1,7 @@ #ifndef SPROUT_MATH_DETAIL_CONFIG_HPP #define SPROUT_MATH_DETAIL_CONFIG_HPP +#include #include #if SPROUT_USE_BUILTIN_CMATH_FUNCTION # include @@ -12,6 +13,12 @@ # define NS_SPROUT_MATH_DETAIL sprout::math::detail #endif // #ifndef SPROUT_USE_BUILTIN_CMATH_FUNCTION +#if (FLT_RADIX == 2) +# define SPROUT_FLT_RADIX_IS_2 1 +#else +# define SPROUT_FLT_RADIX_IS_2 0 +#endif + #if SPROUT_NOERROR_LARGE_FLOAT_ROUNDING # define SPROUT_MATH_THROW_LARGE_FLOAT_ROUNDING(e, x) (x) #else diff --git a/sprout/math/float2_exponent.hpp b/sprout/math/float2_exponent.hpp new file mode 100644 index 00000000..9e84c3a8 --- /dev/null +++ b/sprout/math/float2_exponent.hpp @@ -0,0 +1,38 @@ +#ifndef SPROUT_MATH_FLOAT2_EXPONENT_HPP +#define SPROUT_MATH_FLOAT2_EXPONENT_HPP + +#include +#include +#include +#include +#include + +namespace sprout { + namespace math { + namespace detail { + template< + typename FloatType, + typename sprout::enabler_if::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR int + float2_exponent(FloatType x) { + return sprout::math::ilogb2(x) + 1; + } + + template< + typename IntType, + typename sprout::enabler_if::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR int + float2_exponent(IntType x) { + return sprout::math::detail::float2_exponent(static_cast(x)); + } + } // namespace detail + + using sprout::math::detail::float2_exponent; + } // namespace math + + using sprout::math::float2_exponent; +} // namespace sprout + +#endif // #ifndef SPROUT_MATH_FLOAT2_EXPONENT_HPP diff --git a/sprout/math/float2_sig_exp.hpp b/sprout/math/float2_sig_exp.hpp new file mode 100644 index 00000000..a79a16a4 --- /dev/null +++ b/sprout/math/float2_sig_exp.hpp @@ -0,0 +1,46 @@ +#ifndef SPROUT_MATH_FLOAT2_SIG_EXP_HPP +#define SPROUT_MATH_FLOAT2_SIG_EXP_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace sprout { + namespace math { + namespace detail { + template + inline SPROUT_CONSTEXPR sprout::pair + float2_sig_exp_impl(T x, int exp) { + return sprout::pair(x / sprout::detail::pow_n(T(2), exp), exp); + } + + template< + typename FloatType, + typename sprout::enabler_if::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR sprout::pair + float2_sig_exp(FloatType x) { + return sprout::math::detail::float2_sig_exp_impl(x, sprout::math::float2_exponent(x)); + } + + template< + typename IntType, + typename sprout::enabler_if::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR sprout::pair + float2_sig_exp(IntType x) { + return sprout::math::detail::float2_sig_exp(static_cast(x)); + } + } // namespace detail + + using sprout::math::detail::float2_sig_exp; + } // namespace math + + using sprout::math::float2_sig_exp; +} // namespace sprout + +#endif // #ifndef SPROUT_MATH_FLOAT2_SIG_EXP_HPP diff --git a/sprout/math/float2_significand.hpp b/sprout/math/float2_significand.hpp new file mode 100644 index 00000000..5ae3ce77 --- /dev/null +++ b/sprout/math/float2_significand.hpp @@ -0,0 +1,39 @@ +#ifndef SPROUT_MATH_FLOAT2_SIGNIFICAND_HPP +#define SPROUT_MATH_FLOAT2_SIGNIFICAND_HPP + +#include +#include +#include +#include +#include +#include + +namespace sprout { + namespace math { + namespace detail { + template< + typename FloatType, + typename sprout::enabler_if::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR FloatType + float2_significand(FloatType x) { + return x / sprout::detail::pow_n(FloatType(2), sprout::math::float2_exponent(x)); + } + + template< + typename IntType, + typename sprout::enabler_if::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR double + float2_significand(IntType x) { + return sprout::math::detail::float_significand(static_cast(x)); + } + } // namespace detail + + using sprout::math::detail::float2_significand; + } // namespace math + + using sprout::math::float2_significand; +} // namespace sprout + +#endif // #ifndef SPROUT_MATH_FLOAT2_SIGNIFICAND_HPP diff --git a/sprout/math/float_frac_int.hpp b/sprout/math/float_frac_int.hpp new file mode 100644 index 00000000..6e0d23f8 --- /dev/null +++ b/sprout/math/float_frac_int.hpp @@ -0,0 +1,45 @@ +#ifndef SPROUT_MATH_FLOAT_FRAC_INT_HPP +#define SPROUT_MATH_FLOAT_FRAC_INT_HPP + +#include +#include +#include +#include +#include +#include + +namespace sprout { + namespace math { + namespace detail { + template + inline SPROUT_CONSTEXPR sprout::pair + float_frac_int_impl(T x, T ipart) { + return sprout::pair(x - ipart, ipart); + } + + template< + typename FloatType, + typename sprout::enabler_if::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR sprout::pair + float_frac_int(FloatType x) { + return sprout::math::detail::float_frac_int_impl(x, sprout::math::float_integer_part(x)); + } + + template< + typename IntType, + typename sprout::enabler_if::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR sprout::pair + float_frac_int(IntType x) { + return sprout::math::detail::float_frac_int(static_cast(x)); + } + } // namespace detail + + using sprout::math::detail::float_frac_int; + } // namespace math + + using sprout::math::float_frac_int; +} // namespace sprout + +#endif // #ifndef SPROUT_MATH_FLOAT_FRAC_INT_HPP diff --git a/sprout/math/float_fractional_part.hpp b/sprout/math/float_fractional_part.hpp new file mode 100644 index 00000000..f1596cd7 --- /dev/null +++ b/sprout/math/float_fractional_part.hpp @@ -0,0 +1,38 @@ +#ifndef SPROUT_MATH_FLOAT_FRACTIONAL_PART_HPP +#define SPROUT_MATH_FLOAT_FRACTIONAL_PART_HPP + +#include +#include +#include +#include +#include + +namespace sprout { + namespace math { + namespace detail { + template< + typename FloatType, + typename sprout::enabler_if::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR FloatType + float_fractional_part(FloatType x) { + return x - sprout::math::float_integer_part(x); + } + + template< + typename IntType, + typename sprout::enabler_if::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR double + float_fractional_part(IntType x) { + return sprout::math::detail::float_fractional_part(static_cast(x)); + } + } // namespace detail + + using sprout::math::detail::float_fractional_part; + } // namespace math + + using sprout::math::float_fractional_part; +} // namespace sprout + +#endif // #ifndef SPROUT_MATH_FLOAT_FRACTIONAL_PART_HPP diff --git a/sprout/math/float_integer_part.hpp b/sprout/math/float_integer_part.hpp new file mode 100644 index 00000000..efd08471 --- /dev/null +++ b/sprout/math/float_integer_part.hpp @@ -0,0 +1,38 @@ +#ifndef SPROUT_MATH_FLOAT_INTEGER_PART_HPP +#define SPROUT_MATH_FLOAT_INTEGER_PART_HPP + +#include +#include +#include +#include +#include + +namespace sprout { + namespace math { + namespace detail { + template< + typename FloatType, + typename sprout::enabler_if::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR FloatType + float_integer_part(FloatType x) { + return sprout::math::floor(x); + } + + template< + typename IntType, + typename sprout::enabler_if::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR double + float_integer_part(IntType x) { + return sprout::math::detail::float_integer_part(static_cast(x)); + } + } // namespace detail + + using sprout::math::detail::float_integer_part; + } // namespace math + + using sprout::math::float_integer_part; +} // namespace sprout + +#endif // #ifndef SPROUT_MATH_FLOAT_INTEGER_PART_HPP diff --git a/sprout/math/float_pair.hpp b/sprout/math/float_sig_exp.hpp similarity index 65% rename from sprout/math/float_pair.hpp rename to sprout/math/float_sig_exp.hpp index 386e57b8..425e5484 100644 --- a/sprout/math/float_pair.hpp +++ b/sprout/math/float_sig_exp.hpp @@ -1,5 +1,5 @@ -#ifndef SPROUT_MATH_FLOAT_PAIR_HPP -#define SPROUT_MATH_FLOAT_PAIR_HPP +#ifndef SPROUT_MATH_FLOAT_SIG_EXP_HPP +#define SPROUT_MATH_FLOAT_SIG_EXP_HPP #include #include @@ -15,7 +15,7 @@ namespace sprout { namespace detail { template inline SPROUT_CONSTEXPR sprout::pair - float_pair_impl(T x, int exp) { + float_sig_exp_impl(T x, int exp) { return sprout::pair(x / sprout::detail::pow_n(T(std::numeric_limits::radix), exp), exp); } @@ -24,8 +24,8 @@ namespace sprout { typename sprout::enabler_if::value>::type = sprout::enabler > inline SPROUT_CONSTEXPR sprout::pair - float_pair(FloatType x) { - return sprout::math::detail::float_pair_impl(x, sprout::math::float_exponent(x)); + float_sig_exp(FloatType x) { + return sprout::math::detail::float_sig_exp_impl(x, sprout::math::float_exponent(x)); } template< @@ -33,15 +33,15 @@ namespace sprout { typename sprout::enabler_if::value>::type = sprout::enabler > inline SPROUT_CONSTEXPR sprout::pair - float_pair(IntType x) { - return sprout::math::detail::float_pair(static_cast(x)); + float_sig_exp(IntType x) { + return sprout::math::detail::float_sig_exp(static_cast(x)); } } // namespace detail - using sprout::math::detail::float_pair; + using sprout::math::detail::float_sig_exp; } // namespace math - using sprout::math::float_pair; + using sprout::math::float_sig_exp; } // namespace sprout -#endif // #ifndef SPROUT_MATH_FLOAT_PAIR_HPP +#endif // #ifndef SPROUT_MATH_FLOAT_SIG_EXP_HPP diff --git a/sprout/math/float_mantissa.hpp b/sprout/math/float_significand.hpp similarity index 66% rename from sprout/math/float_mantissa.hpp rename to sprout/math/float_significand.hpp index 0d66f7be..c582b5b1 100644 --- a/sprout/math/float_mantissa.hpp +++ b/sprout/math/float_significand.hpp @@ -1,5 +1,5 @@ -#ifndef SPROUT_MATH_FLOAT_MANTISSA_HPP -#define SPROUT_MATH_FLOAT_MANTISSA_HPP +#ifndef SPROUT_MATH_FLOAT_SIGNIFICAND_HPP +#define SPROUT_MATH_FLOAT_SIGNIFICAND_HPP #include #include @@ -17,7 +17,7 @@ namespace sprout { typename sprout::enabler_if::value>::type = sprout::enabler > inline SPROUT_CONSTEXPR FloatType - float_mantissa(FloatType x) { + float_significand(FloatType x) { return x / sprout::detail::pow_n(FloatType(std::numeric_limits::radix), sprout::math::float_exponent(x)); } @@ -26,15 +26,15 @@ namespace sprout { typename sprout::enabler_if::value>::type = sprout::enabler > inline SPROUT_CONSTEXPR double - float_mantissa(IntType x) { - return sprout::math::detail::float_mantissa(static_cast(x)); + float_significand(IntType x) { + return sprout::math::detail::float_significand(static_cast(x)); } } // namespace detail - using sprout::math::detail::float_mantissa; + using sprout::math::detail::float_significand; } // namespace math - using sprout::math::float_mantissa; + using sprout::math::float_significand; } // namespace sprout -#endif // #ifndef SPROUT_MATH_FLOAT_MANTISSA_HPP +#endif // #ifndef SPROUT_MATH_FLOAT_SIGNIFICAND_HPP diff --git a/sprout/math/floating_point.hpp b/sprout/math/floating_point.hpp index 524e7552..b0c30602 100644 --- a/sprout/math/floating_point.hpp +++ b/sprout/math/floating_point.hpp @@ -7,8 +7,16 @@ #include #include #include +#include +#include +#include #include -#include -#include +#include +#include +#include +#include +#include +#include +#include #endif // #ifndef SPROUT_MATH_FLOATING_POINT_HPP diff --git a/sprout/math/iceil.hpp b/sprout/math/iceil.hpp new file mode 100644 index 00000000..4ad04ef9 --- /dev/null +++ b/sprout/math/iceil.hpp @@ -0,0 +1,75 @@ +#ifndef SPROUT_MATH_ICEIL_HPP +#define SPROUT_MATH_ICEIL_HPP + +#include +#include +#include +#include +#include +#include +#if SPROUT_USE_BUILTIN_CMATH_FUNCTION +# include +#else +# include +#endif + +namespace sprout { + namespace math { + namespace detail { +#if SPROUT_USE_BUILTIN_CMATH_FUNCTION + template + inline SPROUT_CONSTEXPR To + iceil_impl(FloatType x) { + return std::numeric_limits::max() < x || std::numeric_limits::min() > x + ? SPROUT_MATH_THROW_LARGE_FLOAT_ROUNDING(std::domain_error("iceil: large float rounding."), static_cast(x)) + : static_cast(x) + ; + } + template< + typename To = int, + typename FloatType, + typename sprout::enabler_if::value && std::is_integral::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR To + iceil(FloatType x) { + return sprout::math::detail::iceil_impl(sprout::math::ceil(x)); + } +#else + template + inline SPROUT_CONSTEXPR To + iceil_impl(FloatType x, To x0) { + return sprout::math::equal_to(x, x0) ? x0 + : x0 + 1 + ; + } + template< + typename To = int, + typename FloatType, + typename sprout::enabler_if::value && std::is_integral::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR To + iceil(FloatType x) { + return std::numeric_limits::max() < x || std::numeric_limits::min() > x + ? SPROUT_MATH_THROW_LARGE_FLOAT_ROUNDING(std::domain_error("iceil: large float rounding."), static_cast(x)) + : sprout::math::detail::iceil_impl(x, static_cast(x)) + ; + } +#endif + template< + typename To = int, + typename IntType, + typename sprout::enabler_if::value && std::is_integral::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR To + iceil(IntType x) { + return sprout::math::detail::iceil(static_cast(x)); + } + } // namespace detail + + using sprout::math::detail::iceil; + } // namespace math + + using sprout::math::iceil; +} // namespace sprout + +#endif // #ifndef SPROUT_MATH_ICEIL_HPP diff --git a/sprout/math/ifloor.hpp b/sprout/math/ifloor.hpp new file mode 100644 index 00000000..964e6b06 --- /dev/null +++ b/sprout/math/ifloor.hpp @@ -0,0 +1,75 @@ +#ifndef SPROUT_MATH_IFLOOR_HPP +#define SPROUT_MATH_IFLOOR_HPP + +#include +#include +#include +#include +#include +#include +#if SPROUT_USE_BUILTIN_CMATH_FUNCTION +# include +#else +# include +#endif + +namespace sprout { + namespace math { + namespace detail { +#if SPROUT_USE_BUILTIN_CMATH_FUNCTION + template + inline SPROUT_CONSTEXPR To + ifloor_impl(FloatType x) { + return std::numeric_limits::max() < x || std::numeric_limits::min() > x + ? SPROUT_MATH_THROW_LARGE_FLOAT_ROUNDING(std::domain_error("ifloor: large float rounding."), static_cast(x)) + : static_cast(x) + ; + } + template< + typename To = int, + typename FloatType, + typename sprout::enabler_if::value && std::is_integral::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR To + ifloor(FloatType x) { + return sprout::math::detail::ifloor_impl(sprout::math::floor(x)); + } +#else + template + inline SPROUT_CONSTEXPR To + ifloor_impl(FloatType x, To x0) { + return sprout::math::equal_to(x, x0) ? x0 + : x0 - 1 + ; + } + template< + typename To = int, + typename FloatType, + typename sprout::enabler_if::value && std::is_integral::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR To + ifloor(FloatType x) { + return std::numeric_limits::max() < x || std::numeric_limits::min() > x + ? SPROUT_MATH_THROW_LARGE_FLOAT_ROUNDING(std::domain_error("ifloor: large float rounding."), static_cast(x)) + : sprout::math::detail::ifloor_impl(x, static_cast(x)) + ; + } +#endif + template< + typename To = int, + typename IntType, + typename sprout::enabler_if::value && std::is_integral::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR To + ifloor(IntType x) { + return sprout::math::detail::ifloor(static_cast(x)); + } + } // namespace detail + + using sprout::math::detail::ifloor; + } // namespace math + + using sprout::math::ifloor; +} // namespace sprout + +#endif // #ifndef SPROUT_MATH_IFLOOR_HPP diff --git a/sprout/math/ilogb2.hpp b/sprout/math/ilogb2.hpp new file mode 100644 index 00000000..bad2eafc --- /dev/null +++ b/sprout/math/ilogb2.hpp @@ -0,0 +1,71 @@ +#ifndef SPROUT_MATH_ILOGB2_HPP +#define SPROUT_MATH_ILOGB2_HPP + +#include +#include +#include +#include +#include +#include +#if SPROUT_FLT_RADIX_IS_2 +# include +#else +# include +# include +# include +# include +#endif + +namespace sprout { + namespace math { + namespace detail { +#if SPROUT_FLT_RADIX_IS_2 + template< + typename FloatType, + typename sprout::enabler_if::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR int + ilogb2(FloatType x) { + return sprout::math::ilogb(x); + } + + template< + typename IntType, + typename sprout::enabler_if::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR int + ilogb2(IntType x) { + return sprout::math::ilogb(x); + } +#else + template< + typename FloatType, + typename sprout::enabler_if::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR int + ilogb2(FloatType x) { + return sprout::math::iszero(x) ? FP_ILOGB0 + : sprout::math::isinf(x) ? INT_MAX + : sprout::math::isnan(x) ? FP_ILOGBNAN + : static_cast(sprout::math::logb2(x)) + ; + } + + template< + typename IntType, + typename sprout::enabler_if::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR int + ilogb2(IntType x) { + return sprout::math::detail::ilogb2(static_cast(x)); + } +#endif + } // namespace detail + + using sprout::math::detail::ilogb2; + } // namespace math + + using sprout::math::ilogb2; +} // namespace sprout + +#endif // #ifndef SPROUT_MATH_ILOGB2_HPP diff --git a/sprout/math/iround.hpp b/sprout/math/iround.hpp new file mode 100644 index 00000000..c7920da8 --- /dev/null +++ b/sprout/math/iround.hpp @@ -0,0 +1,83 @@ +#ifndef SPROUT_MATH_IROUND_HPP +#define SPROUT_MATH_IROUND_HPP + +#include +#include +#include +#include +#include +#include +#if SPROUT_USE_BUILTIN_CMATH_FUNCTION +# include +#else +# include +#endif + +namespace sprout { + namespace math { + namespace detail { +#if SPROUT_USE_BUILTIN_CMATH_FUNCTION + template + inline SPROUT_CONSTEXPR To + iround_impl(FloatType x) { + return std::numeric_limits::max() < x || std::numeric_limits::min() > x + ? SPROUT_MATH_THROW_LARGE_FLOAT_ROUNDING(std::domain_error("iround: large float rounding."), static_cast(x)) + : static_cast(x) + ; + } + template< + typename To = int, + typename FloatType, + typename sprout::enabler_if::value && std::is_integral::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR To + iround(FloatType x) { + return sprout::math::detail::iround_impl(sprout::math::round(x)); + } +#else + template + inline SPROUT_CONSTEXPR To + iround_impl_positive(FloatType x, To x0) { + return x - x0 < FloatType(0.5) ? x0 + : x0 + 1 + ; + } + template + inline SPROUT_CONSTEXPR To + iround_impl_nagative(FloatType x, To x0) { + return x0 - x < FloatType(0.5) ? x0 + : x0 - 1 + ; + } + template< + typename To = int, + typename FloatType, + typename sprout::enabler_if::value && std::is_integral::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR To + iround(FloatType x) { + return std::numeric_limits::max() < x || std::numeric_limits::min() > x + ? SPROUT_MATH_THROW_LARGE_FLOAT_ROUNDING(std::domain_error("iround: large float irounding."), x) + : x < 0 ? sprout::math::detail::iround_impl_nagative(x, static_cast(x)) + : sprout::math::detail::iround_impl_positive(x, static_cast(x)) + ; + } +#endif + template< + typename To = int, + typename IntType, + typename sprout::enabler_if::value && std::is_integral::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR To + iround(IntType x) { + return sprout::math::detail::iround(static_cast(x)); + } + } // namespace detail + + using sprout::math::detail::iround; + } // namespace math + + using sprout::math::iround; +} // namespace sprout + +#endif // #ifndef SPROUT_MATH_IROUND_HPP diff --git a/sprout/math/itrunc.hpp b/sprout/math/itrunc.hpp new file mode 100644 index 00000000..d1f2ff30 --- /dev/null +++ b/sprout/math/itrunc.hpp @@ -0,0 +1,66 @@ +#ifndef SPROUT_MATH_ITRUNC_HPP +#define SPROUT_MATH_ITRUNC_HPP + +#include +#include +#include +#include +#include +#include +#if SPROUT_USE_BUILTIN_CMATH_FUNCTION +# include +#endif + +namespace sprout { + namespace math { + namespace detail { +#if SPROUT_USE_BUILTIN_CMATH_FUNCTION + template + inline SPROUT_CONSTEXPR To + itrunc_impl(FloatType x) { + return std::numeric_limits::max() < x || std::numeric_limits::min() > x + ? SPROUT_MATH_THROW_LARGE_FLOAT_ROUNDING(std::domain_error("itrunc: large float rounding."), static_cast(x)) + : static_cast(x) + ; + } + template< + typename To = int, + typename FloatType, + typename sprout::enabler_if::value && std::is_integral::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR To + itrunc(FloatType x) { + return sprout::math::detail::itrunc_impl(sprout::math::trunc(x)); + } +#else + template< + typename To = int, + typename FloatType, + typename sprout::enabler_if::value && std::is_integral::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR To + itrunc(FloatType x) { + return std::numeric_limits::max() < x || std::numeric_limits::min() > x + ? SPROUT_MATH_THROW_LARGE_FLOAT_ROUNDING(std::domain_error("itrunc: large float rounding."), static_cast(x)) + : static_cast(x) + ; + } +#endif + template< + typename To = int, + typename IntType, + typename sprout::enabler_if::value && std::is_integral::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR To + itrunc(IntType x) { + return sprout::math::detail::itrunc(static_cast(x)); + } + } // namespace detail + + using sprout::math::detail::itrunc; + } // namespace math + + using sprout::math::itrunc; +} // namespace sprout + +#endif // #ifndef SPROUT_MATH_ITRUNC_HPP diff --git a/sprout/math/llround.hpp b/sprout/math/llround.hpp index a890ea29..294be32b 100644 --- a/sprout/math/llround.hpp +++ b/sprout/math/llround.hpp @@ -1,39 +1,22 @@ #ifndef SPROUT_MATH_LLROUND_HPP #define SPROUT_MATH_LLROUND_HPP -#include #include -#include #include #include +#include #include namespace sprout { namespace math { namespace detail { - template - inline SPROUT_CONSTEXPR long long - llround_impl_positive(FloatType x, long long x0) { - return x - x0 < FloatType(0.5) ? x0 - : x0 + 1 - ; - } - template - inline SPROUT_CONSTEXPR long long - llround_impl_nagative(FloatType x, long long x0) { - return x0 - x < FloatType(0.5) ? x0 - : x0 - 1 - ; - } template< typename FloatType, typename sprout::enabler_if::value>::type = sprout::enabler > inline SPROUT_CONSTEXPR long long llround(FloatType x) { - return x < 0 ? sprout::math::detail::llround_impl_nagative(x, static_cast(x)) - : sprout::math::detail::llround_impl_positive(x, static_cast(x)) - ; + return sprout::math::iround(x); } template< @@ -42,7 +25,7 @@ namespace sprout { > inline SPROUT_CONSTEXPR long long llround(IntType x) { - return static_cast(x); + return sprout::math::iround(x); } } // namespace detail diff --git a/sprout/math/logb.hpp b/sprout/math/logb.hpp index f6404431..6d59d515 100644 --- a/sprout/math/logb.hpp +++ b/sprout/math/logb.hpp @@ -4,12 +4,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include namespace sprout { @@ -79,13 +79,9 @@ namespace sprout { template inline SPROUT_CONSTEXPR T logb_impl(T x, T exp) { - return std::numeric_limits::max() < exp || std::numeric_limits::min() > exp - ? SPROUT_MATH_THROW_LARGE_FLOAT_ROUNDING(std::domain_error("trunc: large float rounding."), exp) - : sprout::math::detail::logb_impl_1( - x, sprout::detail::pow_n(T(std::numeric_limits::radix), static_cast(exp)), - static_cast(static_cast(exp)) - ) - ; + return sprout::math::detail::logb_impl_1( + x, sprout::detail::pow_n(T(std::numeric_limits::radix), sprout::math::itrunc(exp)), exp + ); } template< diff --git a/sprout/math/logb2.hpp b/sprout/math/logb2.hpp new file mode 100644 index 00000000..3f5ba26a --- /dev/null +++ b/sprout/math/logb2.hpp @@ -0,0 +1,142 @@ +#ifndef SPROUT_MATH_LOGB2_HPP +#define SPROUT_MATH_LOGB2_HPP + +#include +#include +#include +#include +#include +#if SPROUT_FLT_RADIX_IS_2 +# include +#else +# include +# include +# include +# include +# include +#endif + +namespace sprout { + namespace math { + namespace detail { +#if SPROUT_FLT_RADIX_IS_2 + template< + typename FloatType, + typename sprout::enabler_if::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR FloatType + logb2(FloatType x) { + return sprout::math::logb(x); + } + + template< + typename IntType, + typename sprout::enabler_if::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR double + logb2(IntType x) { + return sprout::math::logb(x); + } +#else + template + inline SPROUT_CONSTEXPR T + logb2_impl_2_neg_lo(T x, T x0, T base, T exp) { + return base < 1 ? sprout::math::detail::logb2_impl_2_neg_lo( + x, x0 * 2, x / (x0 / 2), exp - 1 + ) + : exp + ; + } + template + inline SPROUT_CONSTEXPR T + logb2_impl_2_neg_hi(T x, T x0, T base, T exp) { + return !(base < 2) ? sprout::math::detail::logb2_impl_2_neg_hi( + x, x0 / 2, x / (x0 * 2), exp + 1 + ) + : exp + ; + } + template + inline SPROUT_CONSTEXPR T + logb2_impl_2_pos_lo(T x, T x0, T base, T exp) { + return base < 1 ? sprout::math::detail::logb2_impl_2_pos_lo( + x, x0 * 2, x / (x0 / 2), exp + 1 + ) + : exp + ; + } + template + inline SPROUT_CONSTEXPR T + logb2_impl_2_pos_hi(T x, T x0, T base, T exp) { + return !(base < 2) ? sprout::math::detail::logb2_impl_2_pos_hi( + x, x0 / 2, x / (x0 * 2), exp - 1 + ) + : exp + ; + } + template + inline SPROUT_CONSTEXPR T + logb2_impl_2(T x, T x0, T base, T exp) { + return exp < 0 + ? base < 1 ? sprout::math::detail::logb2_impl_2_neg_lo( + x, x0 * 2, x / (x0 / 2), exp - 1 + ) + : !(base < 2) ? sprout::math::detail::logb2_impl_2_neg_hi( + x, x0 / 2, x / (x0 * 2), exp + 1 + ) + : exp + : base < 1 ? sprout::math::detail::logb2_impl_2_pos_lo( + x, x0 * 2, x / (x0 / 2), exp + 1 + ) + : !(base < 2) ? sprout::math::detail::logb2_impl_2_pos_hi( + x, x0 / 2, x / (x0 * 2), exp - 1 + ) + : exp + ; + } + template + inline SPROUT_CONSTEXPR T + logb2_impl_1(T x, T x0, T exp) { + return sprout::math::detail::logb2_impl_2(x, x0, x / x0, exp); + } + template + inline SPROUT_CONSTEXPR T + logb2_impl(T x, T exp) { + return sprout::math::detail::logb2_impl_1( + x, sprout::detail::pow_n(T(2), sprout::math::itrunc(exp)), exp + ); + } + + template< + typename FloatType, + typename sprout::enabler_if::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR FloatType + logb2(FloatType x) { + return x < 0 ? sprout::math::detail::logb2_impl( + -x, sprout::math::trunc(sprout::math::log_a(FloatType(2), -x)) + ) + : sprout::math::detail::logb2_impl( + x, sprout::math::trunc(sprout::math::log_a(FloatType(2), x)) + ) + ; + } + + template< + typename IntType, + typename sprout::enabler_if::value>::type = sprout::enabler + > + inline SPROUT_CONSTEXPR double + logb2(IntType x) { + return sprout::math::detail::logb2(static_cast(x)); + } +#endif + } // namespace detail + + using sprout::math::detail::logb2; + } // namespace math + + using sprout::math::logb2; +} // namespace sprout + +#endif // #ifndef SPROUT_MATH_LOGB2_HPP diff --git a/sprout/math/lround.hpp b/sprout/math/lround.hpp index c073d584..8cfb020c 100644 --- a/sprout/math/lround.hpp +++ b/sprout/math/lround.hpp @@ -1,39 +1,22 @@ #ifndef SPROUT_MATH_LROUND_HPP #define SPROUT_MATH_LROUND_HPP -#include #include -#include #include #include +#include #include namespace sprout { namespace math { namespace detail { - template - inline SPROUT_CONSTEXPR long - lround_impl_positive(FloatType x, long x0) { - return x - x0 < FloatType(0.5) ? x0 - : x0 + 1 - ; - } - template - inline SPROUT_CONSTEXPR long - lround_impl_nagative(FloatType x, long x0) { - return x0 - x < FloatType(0.5) ? x0 - : x0 - 1 - ; - } template< typename FloatType, typename sprout::enabler_if::value>::type = sprout::enabler > inline SPROUT_CONSTEXPR long lround(FloatType x) { - return x < 0 ? sprout::math::detail::lround_impl_nagative(x, static_cast(x)) - : sprout::math::detail::lround_impl_positive(x, static_cast(x)) - ; + return sprout::math::iround(x); } template< @@ -42,7 +25,7 @@ namespace sprout { > inline SPROUT_CONSTEXPR long lround(IntType x) { - return static_cast(x); + return sprout::math::iround(x); } } // namespace detail diff --git a/sprout/math/nearest.hpp b/sprout/math/nearest.hpp index 15dffcd9..176b4b55 100644 --- a/sprout/math/nearest.hpp +++ b/sprout/math/nearest.hpp @@ -6,6 +6,10 @@ #include #include #include +#include +#include +#include +#include #include #include