1
2
3
4
5#include <stdlib.h>
6
7#include "rte_approx.h"
8
9
10
11
12
13
14
15
16
17
18
19
20
21static inline uint32_t
22less(uint32_t a, uint32_t b, uint32_t c, uint32_t d)
23{
24 return a*d < b*c;
25}
26
27static inline uint32_t
28less_or_equal(uint32_t a, uint32_t b, uint32_t c, uint32_t d)
29{
30 return a*d <= b*c;
31}
32
33
34static inline uint32_t
35matches(uint32_t a, uint32_t b,
36 uint32_t alpha_num, uint32_t d_num, uint32_t denum)
37{
38 if (less_or_equal(a, b, alpha_num - d_num, denum))
39 return 0;
40
41 if (less(a ,b, alpha_num + d_num, denum))
42 return 1;
43
44 return 0;
45}
46
47static inline void
48find_exact_solution_left(uint32_t p_a, uint32_t q_a, uint32_t p_b, uint32_t q_b,
49 uint32_t alpha_num, uint32_t d_num, uint32_t denum, uint32_t *p, uint32_t *q)
50{
51 uint32_t k_num = denum * p_b - (alpha_num + d_num) * q_b;
52 uint32_t k_denum = (alpha_num + d_num) * q_a - denum * p_a;
53 uint32_t k = (k_num / k_denum) + 1;
54
55 *p = p_b + k * p_a;
56 *q = q_b + k * q_a;
57}
58
59static inline void
60find_exact_solution_right(uint32_t p_a, uint32_t q_a, uint32_t p_b, uint32_t q_b,
61 uint32_t alpha_num, uint32_t d_num, uint32_t denum, uint32_t *p, uint32_t *q)
62{
63 uint32_t k_num = - denum * p_b + (alpha_num - d_num) * q_b;
64 uint32_t k_denum = - (alpha_num - d_num) * q_a + denum * p_a;
65 uint32_t k = (k_num / k_denum) + 1;
66
67 *p = p_b + k * p_a;
68 *q = q_b + k * q_a;
69}
70
71static int
72find_best_rational_approximation(uint32_t alpha_num, uint32_t d_num, uint32_t denum, uint32_t *p, uint32_t *q)
73{
74 uint32_t p_a, q_a, p_b, q_b;
75
76
77 if (!((0 < d_num) && (d_num < alpha_num) && (alpha_num < denum) && (d_num + alpha_num < denum))) {
78 return -1;
79 }
80
81
82 p_a = 0;
83 q_a = 1;
84 p_b = 1;
85 q_b = 1;
86
87 while (1) {
88 uint32_t new_p_a, new_q_a, new_p_b, new_q_b;
89 uint32_t x_num, x_denum, x;
90 int aa, bb;
91
92
93 x_num = denum * p_b - alpha_num * q_b;
94 x_denum = - denum * p_a + alpha_num * q_a;
95 x = (x_num + x_denum - 1) / x_denum;
96
97
98 aa = matches(p_b + x * p_a, q_b + x * q_a, alpha_num, d_num, denum);
99 bb = matches(p_b + (x-1) * p_a, q_b + (x - 1) * q_a, alpha_num, d_num, denum);
100 if (aa || bb) {
101 find_exact_solution_left(p_a, q_a, p_b, q_b, alpha_num, d_num, denum, p, q);
102 return 0;
103 }
104
105
106 new_p_a = p_b + (x - 1) * p_a ;
107 new_q_a = q_b + (x - 1) * q_a;
108 new_p_b = p_b + x * p_a ;
109 new_q_b = q_b + x * q_a;
110
111 p_a = new_p_a ;
112 q_a = new_q_a;
113 p_b = new_p_b ;
114 q_b = new_q_b;
115
116
117 x_num = alpha_num * q_b - denum * p_b;
118 x_denum = - alpha_num * q_a + denum * p_a;
119 x = (x_num + x_denum - 1) / x_denum;
120
121
122 aa = matches(p_b + x * p_a, q_b + x * q_a, alpha_num, d_num, denum);
123 bb = matches(p_b + (x - 1) * p_a, q_b + (x - 1) * q_a, alpha_num, d_num, denum);
124 if (aa || bb) {
125 find_exact_solution_right(p_a, q_a, p_b, q_b, alpha_num, d_num, denum, p, q);
126 return 0;
127 }
128
129
130 new_p_a = p_b + (x - 1) * p_a;
131 new_q_a = q_b + (x - 1) * q_a;
132 new_p_b = p_b + x * p_a;
133 new_q_b = q_b + x * q_a;
134
135 p_a = new_p_a;
136 q_a = new_q_a;
137 p_b = new_p_b;
138 q_b = new_q_b;
139 }
140}
141
142int rte_approx(double alpha, double d, uint32_t *p, uint32_t *q)
143{
144 uint32_t alpha_num, d_num, denum;
145
146
147 if (!((0.0 < d) && (d < alpha) && (alpha < 1.0))) {
148 return -1;
149 }
150
151 if ((p == NULL) || (q == NULL)) {
152 return -2;
153 }
154
155
156 denum = 1;
157 while (d < 1) {
158 alpha *= 10;
159 d *= 10;
160 denum *= 10;
161 }
162 alpha_num = (uint32_t) alpha;
163 d_num = (uint32_t) d;
164
165
166 return find_best_rational_approximation(alpha_num, d_num, denum, p, q);
167}
168
169
170static inline uint64_t
171less_64(uint64_t a, uint64_t b, uint64_t c, uint64_t d)
172{
173 return a*d < b*c;
174}
175
176static inline uint64_t
177less_or_equal_64(uint64_t a, uint64_t b, uint64_t c, uint64_t d)
178{
179 return a*d <= b*c;
180}
181
182
183static inline uint64_t
184matches_64(uint64_t a, uint64_t b,
185 uint64_t alpha_num, uint64_t d_num, uint64_t denum)
186{
187 if (less_or_equal_64(a, b, alpha_num - d_num, denum))
188 return 0;
189
190 if (less_64(a, b, alpha_num + d_num, denum))
191 return 1;
192
193 return 0;
194}
195
196static inline void
197find_exact_solution_left_64(uint64_t p_a, uint64_t q_a, uint64_t p_b, uint64_t q_b,
198 uint64_t alpha_num, uint64_t d_num, uint64_t denum, uint64_t *p, uint64_t *q)
199{
200 uint64_t k_num = denum * p_b - (alpha_num + d_num) * q_b;
201 uint64_t k_denum = (alpha_num + d_num) * q_a - denum * p_a;
202 uint64_t k = (k_num / k_denum) + 1;
203
204 *p = p_b + k * p_a;
205 *q = q_b + k * q_a;
206}
207
208static inline void
209find_exact_solution_right_64(uint64_t p_a, uint64_t q_a, uint64_t p_b, uint64_t q_b,
210 uint64_t alpha_num, uint64_t d_num, uint64_t denum, uint64_t *p, uint64_t *q)
211{
212 uint64_t k_num = -denum * p_b + (alpha_num - d_num) * q_b;
213 uint64_t k_denum = -(alpha_num - d_num) * q_a + denum * p_a;
214 uint64_t k = (k_num / k_denum) + 1;
215
216 *p = p_b + k * p_a;
217 *q = q_b + k * q_a;
218}
219
220static int
221find_best_rational_approximation_64(uint64_t alpha_num, uint64_t d_num,
222 uint64_t denum, uint64_t *p, uint64_t *q)
223{
224 uint64_t p_a, q_a, p_b, q_b;
225
226
227 if (!((d_num > 0) && (d_num < alpha_num) &&
228 (alpha_num < denum) && (d_num + alpha_num < denum))) {
229 return -1;
230 }
231
232
233 p_a = 0;
234 q_a = 1;
235 p_b = 1;
236 q_b = 1;
237
238 while (1) {
239 uint64_t new_p_a, new_q_a, new_p_b, new_q_b;
240 uint64_t x_num, x_denum, x;
241 int aa, bb;
242
243
244 x_num = denum * p_b - alpha_num * q_b;
245 x_denum = -denum * p_a + alpha_num * q_a;
246 x = (x_num + x_denum - 1) / x_denum;
247
248
249 aa = matches_64(p_b + x * p_a, q_b + x * q_a, alpha_num, d_num, denum);
250 bb = matches_64(p_b + (x-1) * p_a, q_b + (x - 1) * q_a,
251 alpha_num, d_num, denum);
252 if (aa || bb) {
253 find_exact_solution_left_64(p_a, q_a, p_b, q_b,
254 alpha_num, d_num, denum, p, q);
255 return 0;
256 }
257
258
259 new_p_a = p_b + (x - 1) * p_a;
260 new_q_a = q_b + (x - 1) * q_a;
261 new_p_b = p_b + x * p_a;
262 new_q_b = q_b + x * q_a;
263
264 p_a = new_p_a;
265 q_a = new_q_a;
266 p_b = new_p_b;
267 q_b = new_q_b;
268
269
270 x_num = alpha_num * q_b - denum * p_b;
271 x_denum = -alpha_num * q_a + denum * p_a;
272 x = (x_num + x_denum - 1) / x_denum;
273
274
275 aa = matches_64(p_b + x * p_a, q_b + x * q_a, alpha_num, d_num, denum);
276 bb = matches_64(p_b + (x - 1) * p_a, q_b + (x - 1) * q_a,
277 alpha_num, d_num, denum);
278 if (aa || bb) {
279 find_exact_solution_right_64(p_a, q_a, p_b, q_b,
280 alpha_num, d_num, denum, p, q);
281 return 0;
282 }
283
284
285 new_p_a = p_b + (x - 1) * p_a;
286 new_q_a = q_b + (x - 1) * q_a;
287 new_p_b = p_b + x * p_a;
288 new_q_b = q_b + x * q_a;
289
290 p_a = new_p_a;
291 q_a = new_q_a;
292 p_b = new_p_b;
293 q_b = new_q_b;
294 }
295}
296
297int rte_approx_64(double alpha, double d, uint64_t *p, uint64_t *q)
298{
299 uint64_t alpha_num, d_num, denum;
300
301
302 if (!((0.0 < d) && (d < alpha) && (alpha < 1.0)))
303 return -1;
304
305 if ((p == NULL) || (q == NULL))
306 return -2;
307
308
309 denum = 1;
310 while (d < 1) {
311 alpha *= 10;
312 d *= 10;
313 denum *= 10;
314 }
315 alpha_num = (uint64_t) alpha;
316 d_num = (uint64_t) d;
317
318
319 return find_best_rational_approximation_64(alpha_num, d_num, denum, p, q);
320}
321