oILAB
Loading...
Searching...
No Matches
BestRationalApproximation.h
Go to the documentation of this file.
1/* This file is part of gbLAB.
2 *
3 * gbLAB is distributed without any warranty under the MIT License.
4 */
5
6
7#ifndef gbLAB_BESTRATIONALAPPROXIMATION_H_
8#define gbLAB_BESTRATIONALAPPROXIMATION_H_
9
10#include <math.h>
11
12// https://rosettacode.org/wiki/Convert_decimal_number_to_rational#C
13
14namespace oILAB {
15
17public:
18 // typedef int64_t LongIntType;
19 typedef long long int LongIntType;
20
21private:
22 static std::pair<LongIntType, LongIntType> rat_approx(double f,
23 LongIntType md) {
24 if (fabs(f) < 1.0 / md) {
25 return std::pair<LongIntType, LongIntType>(0, 1);
26 }
27
28 /* a: continued fraction coefficients. */
29 LongIntType a, h[3] = {0, 1, 0}, k[3] = {1, 0, 0};
30 LongIntType x, d, n = 1;
31 long int i, neg = 0;
32
33 if (md <= 1) { // *denom = 1; *num = (LongIntType) f; return;
34 return std::pair<LongIntType, LongIntType>((LongIntType)f, 1);
35 }
36
37 if (f < 0.0) {
38 neg = 1;
39 f = -f;
40 }
41
42 while (f != floor(f)) {
43 n <<= 1;
44 f *= 2;
45 }
46
47 d = f;
48
49 /* continued fraction and check denominator each step */
50 for (i = 0; i < 64; i++) {
51
52 a = n ? d / n : 0;
53 if (i && !a)
54 break;
55
56 x = d;
57 d = n;
58
59 n = x % n;
60
61 x = a;
62 if (k[1] * a + k[0] >= md) {
63 x = (md - k[0]) / k[1];
64 if (x * 2 >= a || k[1] >= md)
65 i = 65;
66 else
67 break;
68 }
69
70 h[2] = x * h[1] + h[0];
71 h[0] = h[1];
72 h[1] = h[2];
73 k[2] = x * k[1] + k[0];
74 k[0] = k[1];
75 k[1] = k[2];
76 }
77 return std::pair<LongIntType, LongIntType>(neg ? -h[1] : h[1], k[1]);
78 }
79
80 const std::pair<LongIntType, LongIntType> intPair;
81
82public:
85
86 BestRationalApproximation(const double &f, const LongIntType &md)
87 : /* init list */ intPair(
88 isfinite(f) ? rat_approx(f, md)
89 : std::pair<LongIntType, LongIntType>(1, 0)),
90 /* init list */ num(intPair.first),
91 /* init list */ den(intPair.second) {}
92
93 };
94
95 } // namespace oILAB
96#endif
const std::pair< LongIntType, LongIntType > intPair
static std::pair< LongIntType, LongIntType > rat_approx(double f, LongIntType md)
BestRationalApproximation(const double &f, const LongIntType &md)