Search code examples
c++11boosttype-conversionarbitrary-precision

Boost, converting between arbitrary precision floating point and integral types


I am utterly baffled as to how one should actually accomplish this, I have mostly managed to get my code to work until I try to run ceil() on a cpp_dec_float<0> type at which point it will explode on me and refuse to cooperate, after careful examination of boost documentation and google searching I have concluded that I cannot locate the answer on my own, thus I turn here to ask for help from infinitely more competent programmers.

#include <iostream>
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <boost/math/special_functions/pow.hpp>
#include <boost/chrono/ceil.hpp>
#include <boost/multiprecision/number.hpp>

namespace mp = boost::multiprecision;
using namespace std;
using namespace boost::math;
using namespace boost::chrono;
using Int = mp::cpp_int;
Int reward(Int baseReward, int percent);

int main(int argc, char** argv)
{

    reward = calcReward(immBase, percent);
    return 0;
}

Int calcReward(Int baseReward, int percent)
{
    using Dec  = mp::number<mp::cpp_dec_float<0>>;
    Dec mult   = 0.1+0.01*percent;
    Dec five   = 5;
    Dec base   = baseReward.convert_to<Dec>();
    Int result = ceil(five*base*mult);

    return result;
}

that's the code when stripped from unnecessary junk, the five variable is a dirty hack to get it to accept the multiplication with the arbitrary precision floating point value (as it just decided to say that there's no matching operator * otherwise). This is rather bemusing and quite frustrating, ceil().convert_to() didn't work either and spat out an arbitrary undecipherable error. (template errors are unreadable)

this code does require the -std=c++11 flag when compiling, as is probably obvious.


Solution

  • The usual culprit is that the result of BMP expressions are not their target types, but still "lazy" expression templates, and they don't have all the implicit conversions. So, you need to evaluate these "manually" (explicitly):

    return Dec(ceil(five*base*mult)).convert_to<Int>();
    

    See it Live On Coliru

    #include <iostream>
    #include <boost/multiprecision/detail/default_ops.hpp>
    #include <boost/multiprecision/cpp_int.hpp>
    #include <boost/multiprecision/cpp_dec_float.hpp>
    #include <boost/math/special_functions/pow.hpp>
    #include <boost/multiprecision/number.hpp>
    
    namespace mp = boost::multiprecision;
    
    using Int = mp::cpp_int;
    
    Int calcReward(Int baseReward, int percent);
    
    int main()
    {
        Int const immBase = 400;
        int const percent = 12;
    
        std::cout << calcReward(immBase, percent);
    }
    
    Int calcReward(Int baseReward, int percent)
    {
        using Dec  = mp::cpp_dec_float_50;
        Dec mult   = 0.1+0.01*percent;
        Dec five   = 5;
        Dec base   = baseReward.convert_to<Dec>();
    
        return Dec(ceil(five*base*mult)).convert_to<Int>();
    }
    

    Notes: