aGrUM  0.20.3
a C++ library for (probabilistic) graphical models
gum::Rational< GUM_SCALAR > Class Template Reference

Class template used to approximate decimal numbers by rationals. More...

#include <agrum/tools/core/math/rational.h>

Static Public Member Functions

Real approximation by rational
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...
 

Detailed Description

template<typename GUM_SCALAR>
class gum::Rational< GUM_SCALAR >

Class template used to approximate decimal numbers by rationals.

Template Parameters
GUM_SCALARThe floating type ( float, double, long double ... ) of the number.

Definition at line 58 of file rational.h.

Member Function Documentation

◆ 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
numeratorThe numerator of the rational.
denominatorThe denominator of the rational.
numberThe constant number we want to approximate using rationals.
den_maxThe constant highest authorized denominator. 1000000 by default.

Definition at line 191 of file rational_tpl.h.

References gum::Set< Key, Alloc >::emplace().

194  {
195  const GUM_SCALAR pnumber = (number > 0) ? number : -number;
196 
197  const uint64_t denMax = (uint64_t)den_max;
198 
200  GUM_SCALAR rnumber = pnumber;
201 
203  std::vector< uint64_t > p({0, 1});
204  std::vector< uint64_t > q({1, 0});
205 
207  std::vector< uint64_t > a;
208 
209  uint64_t p_tmp, q_tmp;
210 
211  uint64_t n;
212  double delta, delta_tmp;
213 
215  while (true) {
216  a.push_back(std::lrint(std::floor(rnumber)));
217 
218  p_tmp = a.back() * p.back() + p[p.size() - 2];
219  q_tmp = a.back() * q.back() + q[q.size() - 2];
220 
221  if (q_tmp > denMax || p_tmp > denMax) break;
222 
223  p.push_back(p_tmp);
224  q.push_back(q_tmp);
225 
226  if (std::fabs(rnumber - a.back()) < 1e-6) break;
227 
228  rnumber = GUM_SCALAR(1.) / (rnumber - a.back());
229  }
230 
231  if (a.size() < 2 || q.back() == denMax || p.back() == denMax) {
232  numerator = p.back();
233  if (number < 0) numerator = -numerator;
234  denominator = q.back();
235  return;
236  }
237 
241  Idx i = Idx(p.size() - 1);
242 
246  for (n = a[i - 1] - 1; n >= (a[i - 1] + 2) / 2; --n) {
247  p_tmp = n * p[i] + p[i - 1];
248  q_tmp = n * q[i] + q[i - 1];
249 
250  if (q_tmp > denMax || p_tmp > denMax) continue;
251 
252  numerator = (int64_t)p_tmp;
253  if (number < 0) numerator = -numerator;
254  denominator = q_tmp;
255  return;
256  } // end of for
257 
258  // Test n = a[i-1]/2
259  n = a[i - 1] / 2;
260  p_tmp = n * p[i] + p[i - 1];
261  q_tmp = n * q[i] + q[i - 1];
262 
263  delta_tmp = std::fabs(pnumber - ((double)p_tmp) / q_tmp);
264  delta = std::fabs(pnumber - ((double)p[i]) / q[i]);
265 
266  if (delta_tmp < delta && q_tmp <= denMax && p_tmp <= denMax) {
267  numerator = (int64_t)p_tmp;
268  if (number < 0) numerator = -numerator;
269  denominator = q_tmp;
270  } else {
271  numerator = (int64_t)p[i];
272  if (number < 0) numerator = -numerator;
273 
274  denominator = q[i];
275  }
276 
278  }
Size Idx
Type for indexes.
Definition: types.h:52
+ Here is the call graph for this function:

◆ 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
numeratorThe numerator of the rational.
denominatorThe denominator of the rational.
numberThe constant number we want to approximate using rationals.
zeroThe positive value below which a number is considered zero. 1e-6 by default.

Definition at line 94 of file rational_tpl.h.

References gum::Set< Key, Alloc >::emplace().

97  {
98  const GUM_SCALAR pnumber = (number > 0) ? number : -number;
99 
101  GUM_SCALAR rnumber = pnumber;
102 
104  std::vector< uint64_t > p({0, 1});
105  std::vector< uint64_t > q({1, 0});
106 
108  std::vector< uint64_t > a;
109 
110  uint64_t p_tmp, q_tmp;
111 
112  uint64_t n;
113  double delta, delta_tmp;
114 
120  while (true) {
121  a.push_back(std::lrint(std::floor(rnumber)));
122  p.push_back(a.back() * p.back() + p[p.size() - 2]);
123  q.push_back(a.back() * q.back() + q[q.size() - 2]);
124 
125  delta = std::fabs(pnumber - (GUM_SCALAR)p.back() / q.back());
126 
127  if (delta < zero) {
128  numerator = (int64_t)p.back();
129  if (number < 0) numerator = -numerator;
130  denominator = q.back();
131  break;
132  }
133 
134  if (std::abs(rnumber - a.back()) < 1e-6) break;
135 
136  rnumber = GUM_SCALAR(1.) / (rnumber - a.back());
137  }
138 
139  if (a.size() < 2) return;
140 
144  Idx i = Idx(p.size() - 2);
148  // Test n = a[i-1]/2 ( when a[i-1] is even )
149  n = a[i - 1] / 2;
150  p_tmp = n * p[i] + p[i - 1];
151  q_tmp = n * q[i] + q[i - 1];
152 
153  delta = std::fabs(pnumber - ((double)p[i]) / q[i]);
154  delta_tmp = std::fabs(pnumber - ((double)p_tmp) / q_tmp);
155 
156  if (delta < zero) {
157  numerator = (int64_t)p[i];
158  if (number < 0) numerator = -numerator;
159  denominator = q[i];
160  return;
161  }
162 
163  if (delta_tmp < zero) {
164  numerator = (int64_t)p_tmp;
165  if (number < 0) numerator = -numerator;
166  denominator = q_tmp;
167  return;
168  }
169 
170  // next semi-convergents until next convergent from smaller denominator to
171  // bigger
172  // denominator
173  for (n = (a[i - 1] + 2) / 2; n < a[i - 1]; ++n) {
174  p_tmp = n * p[i] + p[i - 1];
175  q_tmp = n * q[i] + q[i - 1];
176 
177  delta_tmp = std::fabs(pnumber - ((double)p_tmp) / q_tmp);
178 
179  if (delta_tmp < zero) {
180  numerator = (int64_t)p_tmp;
181  if (number < 0) numerator = -numerator;
182  denominator = q_tmp;
183  return;
184  }
185  }
186 
188  }
Potential< GUM_SCALAR > abs(const Potential< GUM_SCALAR > &arg)
Definition: potential.h:595
Size Idx
Type for indexes.
Definition: types.h:52
+ Here is the call graph for this function:

◆ 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
numeratorThe numerator of the rational.
denominatorThe denominator of the rational.
numberThe constant number we want to approximate using rationals.
den_maxThe constant highest authorized denominator. 1000000 by default.
zeroThe positive value below which a number is considered zero. 1e-6 by default.

Definition at line 35 of file rational_tpl.h.

References gum::Set< Key, Alloc >::emplace().

39  {
40  bool isNegative = (number < 0) ? true : false;
41  GUM_SCALAR pnumber = (isNegative) ? -number : number;
42 
43  if (std::abs(pnumber - GUM_SCALAR(1.)) < zero) {
44  numerator = (isNegative) ? -1 : 1;
45  denominator = 1;
46  return;
47  } else if (pnumber < zero) {
48  numerator = 0;
49  denominator = 1;
50  return;
51  }
52 
53  int64_t a(0), b(1), c(1), d(1);
54  double mediant(0.0F);
55 
56  while (b <= den_max && d <= den_max) {
57  mediant = (GUM_SCALAR)(a + c) / (GUM_SCALAR)(b + d);
58 
59  if (std::fabs(pnumber - mediant) < zero) {
60  if (b + d <= den_max) {
61  numerator = (isNegative) ? -(a + c) : (a + c);
62  denominator = b + d;
63  return;
64  } else if (d > b) {
65  numerator = (isNegative) ? -c : c;
66  denominator = d;
67  return;
68  } else {
69  numerator = (isNegative) ? -a : a;
70  denominator = b;
71  return;
72  }
73  } else if (pnumber > mediant) {
74  a = a + c;
75  b = b + d;
76  } else {
77  c = a + c;
78  d = b + d;
79  }
80  }
81 
82  if (b > den_max) {
83  numerator = (isNegative) ? -c : c;
84  denominator = d;
85  return;
86  } else {
87  numerator = (isNegative) ? -a : a;
88  denominator = b;
89  return;
90  }
91  }
Potential< GUM_SCALAR > abs(const Potential< GUM_SCALAR > &arg)
Definition: potential.h:595
+ Here is the call graph for this function:

The documentation for this class was generated from the following files: