From 261e433a1b11e2af2877d600419bf262f0b5b80a Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Sun, 8 Jun 2014 18:55:11 +0100 Subject: [PATCH] Add scalbn and logb functions, plus float->rational generic conversion (base 2 only at present). --- .../boost/multiprecision/cpp_dec_float.hpp | 15 ++++++++ .../multiprecision/detail/default_ops.hpp | 23 ++++++++++++ .../detail/generic_interconvert.hpp | 37 +++++++++++++++++++ 3 files changed, 75 insertions(+) diff --git a/include/boost/multiprecision/cpp_dec_float.hpp b/include/boost/multiprecision/cpp_dec_float.hpp index 7c0dc7aa..e63535b3 100644 --- a/include/boost/multiprecision/cpp_dec_float.hpp +++ b/include/boost/multiprecision/cpp_dec_float.hpp @@ -2805,6 +2805,21 @@ inline void eval_trunc(cpp_dec_float& result, result = x.extract_integer_part(); } +template +inline void eval_logb(cpp_dec_float& result, const cpp_dec_float& val) +{ + // Set result, to the exponent of val: + result = static_cast(val.order()); +} +template +inline void eval_scalbn(cpp_dec_float& result, const cpp_dec_float& val, ArgType e_) +{ + using default_ops::eval_multiply; + const ExponentType e = e_; + cpp_dec_float t(1.0, e); + eval_multiply(result, val, t); +} + template inline void eval_ldexp(cpp_dec_float& result, const cpp_dec_float& x, ArgType e) { diff --git a/include/boost/multiprecision/detail/default_ops.hpp b/include/boost/multiprecision/detail/default_ops.hpp index c34177c1..d3bfc082 100644 --- a/include/boost/multiprecision/detail/default_ops.hpp +++ b/include/boost/multiprecision/detail/default_ops.hpp @@ -1202,6 +1202,23 @@ template typename enable_if_c::type eval_ldexp(); template typename enable_if_c::type eval_frexp(); + +// +// eval_logb and eval_scalbn simply assume base 2 and forward to +// eval_ldexp and eval_frexp: +// +template +inline void eval_logb(B& result, const B& val) +{ + typename B::exponent_type e; + eval_frexp(result, val, &e); + result = static_cast(e); +} +template +inline void eval_scalbn(B& result, const B& val, A e) +{ + eval_ldexp(result, val, static_cast(e)); +} // // These functions are implemented in separate files, but expanded inline here, // DO NOT CHANGE THE ORDER OF THESE INCLUDES: @@ -2019,6 +2036,12 @@ BINARY_OP_FUNCTOR(pow, number_kind_floating_point) BINARY_OP_FUNCTOR(fmod, number_kind_floating_point) BINARY_OP_FUNCTOR(atan2, number_kind_floating_point) +UNARY_OP_FUNCTOR(logb, number_kind_floating_point) +HETERO_BINARY_OP_FUNCTOR(scalbn, short, number_kind_floating_point) +HETERO_BINARY_OP_FUNCTOR_B(scalbn, int, number_kind_floating_point) +HETERO_BINARY_OP_FUNCTOR_B(scalbn, long, number_kind_floating_point) +HETERO_BINARY_OP_FUNCTOR_B(scalbn, long long, number_kind_floating_point) + // // Integer functions: // diff --git a/include/boost/multiprecision/detail/generic_interconvert.hpp b/include/boost/multiprecision/detail/generic_interconvert.hpp index 13659724..ddcbada7 100644 --- a/include/boost/multiprecision/detail/generic_interconvert.hpp +++ b/include/boost/multiprecision/detail/generic_interconvert.hpp @@ -222,6 +222,43 @@ void generic_interconvert(To& to, const From& from, const mpl::int_ +void generic_interconvert_float2rational(To& to, const From& from, const mpl::int_<2>& /*radix*/) +{ + BOOST_MATH_STD_USING + typedef typename mpl::front::type ui_type; + static const int shift = std::numeric_limits::digits; + typename From::exponent_type e; + typename component_type::type num, denom; + number val(from); + val = frexp(val, &e); + while(val) + { + val = ldexp(val, shift); + e -= shift; + long long ll = boost::math::lltrunc(val); + val -= ll; + num <<= shift; + num += ll; + } + denom = ui_type(1u); + if(e < 0) + denom <<= -e; + else if(e > 0) + num <<= e; + assign_components(to, num, denom); +} + +} + +template +void generic_interconvert(To& to, const From& from, const mpl::int_& /*to_type*/, const mpl::int_& /*from_type*/) +{ + detail::generic_interconvert_float2rational(to, from, mpl::int_ >::radix>()); +} + }}} // namespaces #endif // BOOST_MP_GENERIC_INTERCONVERT_HPP