1 /* fp2rat.c (convert floating-point number to rational number) */
2 
3 /***********************************************************************
4 *  This code is part of GLPK (GNU Linear Programming Kit).
5 *  Copyright (C) 2000-2013 Free Software Foundation, Inc.
6 *  Written by Andrew Makhorin <mao@gnu.org>.
7 *
8 *  GLPK is free software: you can redistribute it and/or modify it
9 *  under the terms of the GNU General Public License as published by
10 *  the Free Software Foundation, either version 3 of the License, or
11 *  (at your option) any later version.
12 *
13 *  GLPK is distributed in the hope that it will be useful, but WITHOUT
14 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 *  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 *  License for more details.
17 *
18 *  You should have received a copy of the GNU General Public License
19 *  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
20 ***********************************************************************/
21 
22 #include "env.h"
23 #include "misc.h"
24 
25 /***********************************************************************
26 *  NAME
27 *
28 *  fp2rat - convert floating-point number to rational number
29 *
30 *  SYNOPSIS
31 *
32 *  #include "misc.h"
33 *  int fp2rat(double x, double eps, double *p, double *q);
34 *
35 *  DESCRIPTION
36 *
37 *  Given a floating-point number 0 <= x < 1 the routine fp2rat finds
38 *  its "best" rational approximation p / q, where p >= 0 and q > 0 are
39 *  integer numbers, such that |x - p / q| <= eps.
40 *
41 *  RETURNS
42 *
43 *  The routine fp2rat returns the number of iterations used to achieve
44 *  the specified precision eps.
45 *
46 *  EXAMPLES
47 *
48 *  For x = sqrt(2) - 1 = 0.414213562373095 and eps = 1e-6 the routine
49 *  gives p = 408 and q = 985, where 408 / 985 = 0.414213197969543.
50 *
51 *  BACKGROUND
52 *
53 *  It is well known that every positive real number x can be expressed
54 *  as the following continued fraction:
55 *
56 *     x = b[0] + a[1]
57 *                ------------------------
58 *                b[1] + a[2]
59 *                       -----------------
60 *                       b[2] + a[3]
61 *                              ----------
62 *                              b[3] + ...
63 *
64 *  where:
65 *
66 *     a[k] = 1,                  k = 0, 1, 2, ...
67 *
68 *     b[k] = floor(x[k]),        k = 0, 1, 2, ...
69 *
70 *     x[0] = x,
71 *
72 *     x[k] = 1 / frac(x[k-1]),   k = 1, 2, 3, ...
73 *
74 *  To find the "best" rational approximation of x the routine computes
75 *  partial fractions f[k] by dropping after k terms as follows:
76 *
77 *     f[k] = A[k] / B[k],
78 *
79 *  where:
80 *
81 *     A[-1] = 1,   A[0] = b[0],   B[-1] = 0,   B[0] = 1,
82 *
83 *     A[k] = b[k] * A[k-1] + a[k] * A[k-2],
84 *
85 *     B[k] = b[k] * B[k-1] + a[k] * B[k-2].
86 *
87 *  Once the condition
88 *
89 *     |x - f[k]| <= eps
90 *
91 *  has been satisfied, the routine reports p = A[k] and q = B[k] as the
92 *  final answer.
93 *
94 *  In the table below here is some statistics obtained for one million
95 *  random numbers uniformly distributed in the range [0, 1).
96 *
97 *      eps      max p   mean p      max q    mean q  max k   mean k
98 *     -------------------------------------------------------------
99 *     1e-1          8      1.6          9       3.2    3      1.4
100 *     1e-2         98      6.2         99      12.4    5      2.4
101 *     1e-3        997     20.7        998      41.5    8      3.4
102 *     1e-4       9959     66.6       9960     133.5   10      4.4
103 *     1e-5      97403    211.7      97404     424.2   13      5.3
104 *     1e-6     479669    669.9     479670    1342.9   15      6.3
105 *     1e-7    1579030   2127.3    3962146    4257.8   16      7.3
106 *     1e-8   26188823   6749.4   26188824   13503.4   19      8.2
107 *
108 *  REFERENCES
109 *
110 *  W. B. Jones and W. J. Thron, "Continued Fractions: Analytic Theory
111 *  and Applications," Encyclopedia on Mathematics and Its Applications,
112 *  Addison-Wesley, 1980. */
113 
fp2rat(double x,double eps,double * p,double * q)114 int fp2rat(double x, double eps, double *p, double *q)
115 {     int k;
116       double xk, Akm1, Ak, Bkm1, Bk, ak, bk, fk, temp;
117       xassert(0.0 <= x && x < 1.0);
118       for (k = 0; ; k++)
119       {  xassert(k <= 100);
120          if (k == 0)
121          {  /* x[0] = x */
122             xk = x;
123             /* A[-1] = 1 */
124             Akm1 = 1.0;
125             /* A[0] = b[0] = floor(x[0]) = 0 */
126             Ak = 0.0;
127             /* B[-1] = 0 */
128             Bkm1 = 0.0;
129             /* B[0] = 1 */
130             Bk = 1.0;
131          }
132          else
133          {  /* x[k] = 1 / frac(x[k-1]) */
134             temp = xk - floor(xk);
135             xassert(temp != 0.0);
136             xk = 1.0 / temp;
137             /* a[k] = 1 */
138             ak = 1.0;
139             /* b[k] = floor(x[k]) */
140             bk = floor(xk);
141             /* A[k] = b[k] * A[k-1] + a[k] * A[k-2] */
142             temp = bk * Ak + ak * Akm1;
143             Akm1 = Ak, Ak = temp;
144             /* B[k] = b[k] * B[k-1] + a[k] * B[k-2] */
145             temp = bk * Bk + ak * Bkm1;
146             Bkm1 = Bk, Bk = temp;
147          }
148          /* f[k] = A[k] / B[k] */
149          fk = Ak / Bk;
150 #if 0
151          print("%.*g / %.*g = %.*g",
152             DBL_DIG, Ak, DBL_DIG, Bk, DBL_DIG, fk);
153 #endif
154          if (fabs(x - fk) <= eps)
155             break;
156       }
157       *p = Ak;
158       *q = Bk;
159       return k;
160 }
161 
162 /* eof */
163