将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;
}
有更好的主意吗?
至少修复负数,因为现在-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);
}