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