Add scalbn and logb functions, plus float->rational generic conversion (base 2 only at present).

This commit is contained in:
jzmaddock
2014-06-08 18:55:11 +01:00
parent 3eec6eb225
commit 261e433a1b
3 changed files with 75 additions and 0 deletions

View File

@@ -2805,6 +2805,21 @@ inline void eval_trunc(cpp_dec_float<Digits10, ExponentType, Allocator>& result,
result = x.extract_integer_part();
}
template <unsigned Digits10, class ExponentType, class Allocator>
inline void eval_logb(cpp_dec_float<Digits10, ExponentType, Allocator>& result, const cpp_dec_float<Digits10, ExponentType, Allocator>& val)
{
// Set result, to the exponent of val:
result = static_cast<long long>(val.order());
}
template <unsigned Digits10, class ExponentType, class Allocator, class ArgType>
inline void eval_scalbn(cpp_dec_float<Digits10, ExponentType, Allocator>& result, const cpp_dec_float<Digits10, ExponentType, Allocator>& val, ArgType e_)
{
using default_ops::eval_multiply;
const ExponentType e = e_;
cpp_dec_float<Digits10, ExponentType, Allocator> t(1.0, e);
eval_multiply(result, val, t);
}
template <unsigned Digits10, class ExponentType, class Allocator, class ArgType>
inline void eval_ldexp(cpp_dec_float<Digits10, ExponentType, Allocator>& result, const cpp_dec_float<Digits10, ExponentType, Allocator>& x, ArgType e)
{

View File

@@ -1202,6 +1202,23 @@ template <class T>
typename enable_if_c<sizeof(T) == 0>::type eval_ldexp();
template <class T>
typename enable_if_c<sizeof(T) == 0>::type eval_frexp();
//
// eval_logb and eval_scalbn simply assume base 2 and forward to
// eval_ldexp and eval_frexp:
//
template <class B>
inline void eval_logb(B& result, const B& val)
{
typename B::exponent_type e;
eval_frexp(result, val, &e);
result = static_cast<boost::intmax_t>(e);
}
template <class B, class A>
inline void eval_scalbn(B& result, const B& val, A e)
{
eval_ldexp(result, val, static_cast<typename B::exponent_type>(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:
//

View File

@@ -222,6 +222,43 @@ void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_
eval_divide(to, fn.backend(), fd.backend());
}
namespace detail{
template <class To, class From>
void generic_interconvert_float2rational(To& to, const From& from, const mpl::int_<2>& /*radix*/)
{
BOOST_MATH_STD_USING
typedef typename mpl::front<typename To::unsigned_types>::type ui_type;
static const int shift = std::numeric_limits<long long>::digits;
typename From::exponent_type e;
typename component_type<To>::type num, denom;
number<From> 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 <class To, class From>
void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_rational>& /*to_type*/, const mpl::int_<number_kind_floating_point>& /*from_type*/)
{
detail::generic_interconvert_float2rational(to, from, mpl::int_<std::numeric_limits<number<From> >::radix>());
}
}}} // namespaces
#endif // BOOST_MP_GENERIC_INTERCONVERT_HPP