Class template used to approximate decimal numbers by rationals.
More...
#include <agrum/core/math/rational.h>
|
|
static void | farey (int64_t &numerator, int64_t &denominator, const GUM_SCALAR &number, const int64_t &den_max=1000000L, const GUM_SCALAR &zero=1e-6) |
| Find the rational close enough to a given ( decimal ) number in [-1,1] and whose denominator is not higher than a given integer number. More...
|
|
static void | continuedFracFirst (int64_t &numerator, int64_t &denominator, const GUM_SCALAR &number, const double &zero=1e-6) |
| Find the first best rational approximation. More...
|
|
static void | continuedFracBest (int64_t &numerator, int64_t &denominator, const GUM_SCALAR &number, const int64_t &den_max=1000000) |
| Find the best rational approximation. More...
|
|
template<typename GUM_SCALAR>
class gum::Rational< GUM_SCALAR >
Class template used to approximate decimal numbers by rationals.
- Template Parameters
-
GUM_SCALAR | The floating type ( float, double, long double ... ) of the number. |
Definition at line 59 of file rational.h.
◆ continuedFracBest()
template<typename GUM_SCALAR >
void gum::Rational< GUM_SCALAR >::continuedFracBest |
( |
int64_t & |
numerator, |
|
|
int64_t & |
denominator, |
|
|
const GUM_SCALAR & |
number, |
|
|
const int64_t & |
den_max = 1000000 |
|
) |
| |
|
static |
Find the best rational approximation.
Not the first, to a given ( decimal) number ( ANY number ) and whose denominator is not higher than a given integer number.
In this case, we look for semi-convergents at the right of the last admissible convergent, if any. They are better approximations, but have higher denominators.
- Parameters
-
numerator | The numerator of the rational. |
denominator | The denominator of the rational. |
number | The constant number we want to approximate using rationals. |
den_max | The constant highest authorized denominator. 1000000 by default. |
Definition at line 192 of file rational_tpl.h.
196 const GUM_SCALAR pnumber = (number > 0) ? number : -number;
198 const uint64_t denMax =
202 GUM_SCALAR rnumber = pnumber;
205 std::vector< uint64_t > p({0, 1});
206 std::vector< uint64_t > q({1, 0});
209 std::vector< uint64_t > a;
211 uint64_t p_tmp, q_tmp;
214 double delta, delta_tmp;
218 a.push_back(std::lrint(std::floor(rnumber)));
220 p_tmp = a.back() * p.back() + p[p.size() - 2];
221 q_tmp = a.back() * q.back() + q[q.size() - 2];
223 if (q_tmp > denMax || p_tmp > denMax)
break;
228 if (std::fabs(rnumber - a.back()) < 1e-6)
break;
230 rnumber = GUM_SCALAR(1.) / (rnumber - a.back());
233 if (a.size() < 2 || q.back() == denMax || p.back() == denMax) {
234 numerator = p.back();
235 if (number < 0) numerator = -numerator;
236 denominator = q.back();
243 Idx i =
Idx(p.size() - 1);
248 for (n = a[i - 1] - 1; n >= (a[i - 1] + 2) / 2; --n) {
249 p_tmp = n * p[i] + p[i - 1];
250 q_tmp = n * q[i] + q[i - 1];
252 if (q_tmp > denMax || p_tmp > denMax)
continue;
254 numerator = (int64_t)p_tmp;
255 if (number < 0) numerator = -numerator;
262 p_tmp = n * p[i] + p[i - 1];
263 q_tmp = n * q[i] + q[i - 1];
265 delta_tmp = std::fabs(pnumber - ((
double)p_tmp) / q_tmp);
266 delta = std::fabs(pnumber - ((
double)p[i]) / q[i]);
268 if (delta_tmp < delta && q_tmp <= denMax && p_tmp <= denMax) {
269 numerator = (int64_t)p_tmp;
270 if (number < 0) numerator = -numerator;
273 numerator = (int64_t)p[i];
274 if (number < 0) numerator = -numerator;
Size Idx
Type for indexes.
◆ continuedFracFirst()
template<typename GUM_SCALAR >
void gum::Rational< GUM_SCALAR >::continuedFracFirst |
( |
int64_t & |
numerator, |
|
|
int64_t & |
denominator, |
|
|
const GUM_SCALAR & |
number, |
|
|
const double & |
zero = 1e-6 |
|
) |
| |
|
static |
Find the first best rational approximation.
end of farey func
The one with the smallest denominator such that no other rational with smaller denominator is a better approx, within precision zero to a given ( decimal ) number ( ANY number).
It gives the same answer than farey assuming zero
is the same and den_max is infinite. Use this functions because you are sure to get an approx within zero
of number
.
We look at the semi-convergents left of the last admissible convergent, if any. They may be within the same precision and have a smaller denominator.
- Parameters
-
numerator | The numerator of the rational. |
denominator | The denominator of the rational. |
number | The constant number we want to approximate using rationals. |
zero | The positive value below which a number is considered zero. 1e-6 by default. |
Definition at line 95 of file rational_tpl.h.
Referenced by gum::credal::LRSWrapper< GUM_SCALAR >::__fill().
99 const GUM_SCALAR pnumber = (number > 0) ? number : -number;
102 GUM_SCALAR rnumber = pnumber;
105 std::vector< uint64_t > p({0, 1});
106 std::vector< uint64_t > q({1, 0});
109 std::vector< uint64_t > a;
111 uint64_t p_tmp, q_tmp;
114 double delta, delta_tmp;
122 a.push_back(std::lrint(std::floor(rnumber)));
123 p.push_back(a.back() * p.back() + p[p.size() - 2]);
124 q.push_back(a.back() * q.back() + q[q.size() - 2]);
126 delta = std::fabs(pnumber - (GUM_SCALAR)p.back() / q.back());
129 numerator = (int64_t)p.back();
130 if (number < 0) numerator = -numerator;
131 denominator = q.back();
135 if (std::abs(rnumber - a.back()) < 1e-6)
break;
137 rnumber = GUM_SCALAR(1.) / (rnumber - a.back());
140 if (a.size() < 2)
return;
145 Idx i =
Idx(p.size() - 2);
151 p_tmp = n * p[i] + p[i - 1];
152 q_tmp = n * q[i] + q[i - 1];
154 delta = std::fabs(pnumber - ((
double)p[i]) / q[i]);
155 delta_tmp = std::fabs(pnumber - ((
double)p_tmp) / q_tmp);
158 numerator = (int64_t)p[i];
159 if (number < 0) numerator = -numerator;
164 if (delta_tmp < zero) {
165 numerator = (int64_t)p_tmp;
166 if (number < 0) numerator = -numerator;
174 for (n = (a[i - 1] + 2) / 2; n < a[i - 1]; ++n) {
175 p_tmp = n * p[i] + p[i - 1];
176 q_tmp = n * q[i] + q[i - 1];
178 delta_tmp = std::fabs(pnumber - ((
double)p_tmp) / q_tmp);
180 if (delta_tmp < zero) {
181 numerator = (int64_t)p_tmp;
182 if (number < 0) numerator = -numerator;
Size Idx
Type for indexes.
◆ farey()
template<typename GUM_SCALAR >
void gum::Rational< GUM_SCALAR >::farey |
( |
int64_t & |
numerator, |
|
|
int64_t & |
denominator, |
|
|
const GUM_SCALAR & |
number, |
|
|
const int64_t & |
den_max = 1000000L , |
|
|
const GUM_SCALAR & |
zero = 1e-6 |
|
) |
| |
|
static |
Find the rational close enough to a given ( decimal ) number in [-1,1] and whose denominator is not higher than a given integer number.
Because of the double constraint on precision and size of the denominator, there is no guarantee on the precision of the approximation if den_max
is low and zero
is high. Prefer the use of continued fractions.
- Parameters
-
numerator | The numerator of the rational. |
denominator | The denominator of the rational. |
number | The constant number we want to approximate using rationals. |
den_max | The constant highest authorized denominator. 1000000 by default. |
zero | The positive value below which a number is considered zero. 1e-6 by default. |
Definition at line 36 of file rational_tpl.h.
Referenced by gum::credal::CredalNet< GUM_SCALAR >::__H2Vlrs().
41 bool isNegative = (number < 0) ?
true :
false;
42 GUM_SCALAR pnumber = (isNegative) ? -number : number;
44 if (std::abs(pnumber - GUM_SCALAR(1.)) < zero) {
45 numerator = (isNegative) ? -1 : 1;
48 }
else if (pnumber < zero) {
54 int64_t a(0), b(1), c(1), d(1);
57 while (b <= den_max && d <= den_max) {
58 mediant = (GUM_SCALAR)(a + c) / (GUM_SCALAR)(b + d);
60 if (std::fabs(pnumber - mediant) < zero) {
61 if (b + d <= den_max) {
62 numerator = (isNegative) ? -(a + c) : (a + c);
66 numerator = (isNegative) ? -c : c;
70 numerator = (isNegative) ? -a : a;
74 }
else if (pnumber > mediant) {
84 numerator = (isNegative) ? -c : c;
88 numerator = (isNegative) ? -a : a;
The documentation for this class was generated from the following files: