将boost :: multiprecision :: mpq_rational舍入到最接近的整数

时间:2014-05-06 14:32:25

标签: c++ boost rounding multiprecision

将boost :: multiprecision :: mpq_rational舍入到最接近的整数的最佳方法是什么?

一个丑陋的解决方案是:

#include <boost/multiprecision/gmp.hpp>
using namespace boost::multiprecision;

inline int round_to_int(mpq_rational v)
{
  mpz_int vf_mpz = numerator(v) / denominator(v);
  mpz_t z;
  mpz_init(z);
  mpz_set(z, vf_mpz.backend().data());
  int vf = mpz_get_si(z);
  if (v - vf_mpz < vf_mpz + 1 - v) return vf;
  else return vf + 1;
}

有更好的想法吗?

1 个答案:

答案 0 :(得分:3)

至少修正负数,因为现在-13/7会转到-1(当-2更接近时)。

此外,由于范围最终应映射到int,只需:

template <typename rational>
inline int round_to_int(rational v)
{
    v = v + typename rational::number(v.sign()) / 2;
    return v.template convert_to<int>();
}

对于负数,这会产生更合理的结果:请参阅 Live On Coliru

-2   -2.00      -2
-13/7    -1.86      -2
-12/7    -1.71      -2
-11/7    -1.57      -2
-10/7    -1.43      -1
-9/7     -1.29      -1
-8/7     -1.14      -1
-1   -1.00      -1
-2   -2.00      -2
-13/7    -1.86      -2
-12/7    -1.71      -2
-11/7    -1.57      -2
-10/7    -1.43      -1
-9/7     -1.29      -1
-8/7     -1.14      -1
-1   -1.00      -1
-6/7     -0.86      -1
-5/7     -0.71      -1
-4/7     -0.57      -1
-3/7     -0.43       0
-2/7     -0.29       0
-1/7     -0.14       0
0     0.00       0
1/7   0.14       0
2/7   0.29       0
3/7   0.43       0
4/7   0.57       1
5/7   0.71       1
6/7   0.86       1
1     1.00       1
8/7   1.14       1
9/7   1.29       1
10/7      1.43       1
11/7      1.57       2
12/7      1.71       2
13/7      1.86       2
2     2.00       2
----------------------
-2   -2.00      -2
-3/2     -1.50      -2
-1   -1.00      -1
-1/2     -0.50      -1
0     0.00       0
1/2   0.50       1
1     1.00       1
3/2   1.50       2
2     2.00       2

完整代码:

#include <boost/multiprecision/mpfr.hpp>
#include <boost/multiprecision/number.hpp>
#include <vector>

using boost::multiprecision::mpq_rational;

template <typename rational>
inline int round_to_int(rational v)
{
    v = v + typename rational::number(v.sign()) / 2;
    return v.template convert_to<int>();
}

int main()
{
    auto show = [](mpq_rational a) { 
        std::cout << std::right << a << "\t" << std::setw(6) << (double) a << "\t" << std::right << std::setw(6) << round_to_int(a) << '\n';
    };
    std::cout << std::fixed << std::setprecision(2);

    for (mpq_rational r(-2); r<=2; r = (r*7+1)/7)
        show(r);
    std::cout << "----------------------\n";
    for (mpq_rational r(-2); r<=2; r = (r*2+1)/2)
        show(r);
}