Search code examples
c++boostroundingmultiprecision

Force cpp_dec_float to round down


I am using .str(n, std::ios_base::scientific) to print ccp_dec_floats.

I've noticed that it rounds up.

I am using cpp_dec_float for accounting, so I need to round downward. How can this be done?


Solution

  • It doesn't round up. In fact, it does banker's round: See it Live On Coliru

    #include <boost/multiprecision/number.hpp>
    #include <boost/multiprecision/cpp_int.hpp>
    #include <boost/multiprecision/cpp_dec_float.hpp>
    #include <iostream>
    
    namespace mp = boost::multiprecision;
    
    int main()
    {
        using Dec = mp::cpp_dec_float_50;
    
        for (Dec d : { 
                Dec( "3.34"),   Dec( "3.35"),   Dec( "3.38"),
                Dec( "2.24"),   Dec( "2.25"),   Dec( "2.28"),
                Dec("-2.24"),   Dec("-2.25"),   Dec("-2.28"),
                Dec("-3.34"),   Dec("-3.35"),   Dec("-3.38"),
                })
        {
            std::cout     << d.str(2, std::ios_base::fixed) 
                << " -> " << d.str(1, std::ios_base::fixed) << "\n";
        }
    }
    

    Prints:

    3.34 -> 3.3
    3.35 -> 3.4
    3.38 -> 3.4
    2.24 -> 2.2
    2.25 -> 2.2
    2.28 -> 2.3
    -2.24 -> -2.2
    -2.25 -> -2.2
    -2.28 -> -2.3
    -3.34 -> -3.3
    -3.35 -> -3.4
    -3.38 -> -3.4
    

    So if you want another kind of rounding, you'd want to write it explicitly

    Here's a generic approach (Live On Coliru)

    template <int decimals = 0, typename T>
    T round_towards_zero(T const& v)
    {
        static const T scale = pow(T(10), decimals);
    
        if (v.is_zero())
            return v;
    
        // ceil/floor is found via ADL and uses expression templates for optimization
        if (v<0)
            return ceil(v*scale)/scale;
        else
            // floor is found via ADL and uses expression templates for optimization
            return floor(v*scale)/scale;
    }
    

    which hopefully compiles down to optimal code due to statically known scale factor and the use of expression templates in Boost Multiprecision library.