Каков наилучший способ округлить 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>();
}
Это приводит к более разумным результатам, для отрицательных чисел: посмотрите это Жить на Колиру
-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);
}