Search code examples
c++boostroundingrational-number

boost rational_cast with rounding?


How can I do a rational_cast<int64_t> with rounding?

Currently I'm doing a hack like this:

boost::rational<int64_t> pts = ..., time_base = ...;
int64_t rounded = std::llround(boost::rational_cast<long double>(pts / time_base)); 

But I'd like to be able to do it "properly" without involving floating point.


Solution

  • Rounding is inherently lossy.

    The quickest hack that comes to mind is simply using the built-in behaviour (which is floor-ing or trunc-ing the result) and offset by a half:

    Live On Coliru

    #include <iostream>
    #include <fstream>
    #include <boost/rational.hpp>
    
    int main() {
        using R = boost::rational<int64_t>;
        for (auto den : {5,6}) {
            std::cout << "---------\n";
            for (auto num : {1,2,3,4,5,6}) {
                R pq(num, den);
                std::cout << num << "/" << den << " = " << pq << ": " 
                          << boost::rational_cast<int64_t>(pq + R(1,2)) << "\n";
            }
        }
    }
    

    Prints

    ---------
    1/5 = 1/5: 0
    2/5 = 2/5: 0
    3/5 = 3/5: 1
    4/5 = 4/5: 1
    5/5 = 1/1: 1
    6/5 = 6/5: 1
    ---------
    1/6 = 1/6: 0
    2/6 = 1/3: 0
    3/6 = 1/2: 1
    4/6 = 2/3: 1
    5/6 = 5/6: 1
    6/6 = 1/1: 1