#ifndef SPROUT_DETAIL_FLOAT_HPP #define SPROUT_DETAIL_FLOAT_HPP #include #include #include #include #include #include #include #include namespace sprout { namespace detail { // // float_pow10 // template< typename FloatType, typename sprout::enabler_if::value>::type = sprout::enabler > inline SPROUT_CONSTEXPR FloatType float_pow10(int exponent) { return sprout::detail::pow_n(FloatType(10), exponent); } // // float_exponent10 // // !!! template inline SPROUT_CONSTEXPR int float_exponent10_positive(FloatType val) { return val < 10 ? 0 : 1 + sprout::detail::float_exponent10_positive(val / 10) ; } template inline SPROUT_CONSTEXPR int float_exponent10_negative(FloatType val) { return val < 1 ? 1 + sprout::detail::float_exponent10_negative(val * 10) : 0 ; } template< typename FloatType, typename sprout::enabler_if::value>::type = sprout::enabler > inline SPROUT_CONSTEXPR int float_exponent10(FloatType val) { return val < 0 ? val > -1 ? sprout::detail::float_exponent10_negative(-val) : sprout::detail::float_exponent10_positive(-val) : val < 1 ? sprout::detail::float_exponent10_negative(val) : sprout::detail::float_exponent10_positive(val) ; } // // float_digit_at // template inline SPROUT_CONSTEXPR int float_digit_of_impl(FloatType val) { return static_cast((val - sprout::math::floor(val)) * 10); } template< typename FloatType, typename sprout::enabler_if::value>::type = sprout::enabler > inline SPROUT_CONSTEXPR int float_digit_at(FloatType val, int digits) { return sprout::detail::float_digit_of_impl(val / sprout::detail::float_pow10(digits + 1)); } // // float_digits // template inline SPROUT_CONSTEXPR sprout::pair float_digits_impl_1(sprout::pair const& current, FloatType val, int n) { typedef sprout::pair type; return (val / current.second) < 1 ? current : n == 1 ? type(current.first + 1, current.second * FloatType(10)) : sprout::detail::float_digits_impl_1( sprout::detail::float_digits_impl_1( current, val, n / 2 ), val, n - n / 2 ) ; } template inline SPROUT_CONSTEXPR sprout::pair float_digits_impl(sprout::pair const& current, FloatType val, int n) { return (val / current.second) < 1 ? current : sprout::detail::float_digits_impl( sprout::detail::float_digits_impl_1( current, val, n ), val, n * 2 ) ; } template< typename FloatType, typename sprout::enabler_if::value>::type = sprout::enabler > inline SPROUT_CONSTEXPR int float_digits(FloatType val) { typedef sprout::pair type; return val < 0 ? val > -1 ? 1 : sprout::detail::float_digits_impl(type(1, FloatType(10)), -val, 1).first : val < 1 ? 1 : sprout::detail::float_digits_impl(type(1, FloatType(10)), val, 1).first ; } // // float_digits_checked // template inline SPROUT_CONSTEXPR int float_digits_checked_impl(FloatType val, int digits) { return val == 0 ? digits : sprout::detail::float_digit_at(val, digits - 1) == 0 ? digits - 1 : digits ; } template< typename FloatType, typename sprout::enabler_if::value>::type = sprout::enabler > inline SPROUT_CONSTEXPR int float_digits_checked(FloatType val) { return sprout::detail::float_digits_checked_impl(val, sprout::detail::float_digits(val)); } // // float_round_at // template inline SPROUT_CONSTEXPR FloatType float_round_impl(FloatType val, FloatType p10) { return sprout::math::round(val * p10) / p10; } template< typename FloatType, typename sprout::enabler_if::value>::type = sprout::enabler > inline SPROUT_CONSTEXPR FloatType float_round_at(FloatType val, int digits) { return sprout::detail::float_round_impl(val, sprout::detail::float_pow10(digits)); } } // namespace detail } // namespace sprout #endif // #ifndef SPROUT_DETAIL_FLOAT_HPP