12c64e9cbSAndy Shevchenko // SPDX-License-Identifier: GPL-2.0
22c64e9cbSAndy Shevchenko /*
32c64e9cbSAndy Shevchenko * rational fractions
42c64e9cbSAndy Shevchenko *
52c64e9cbSAndy Shevchenko * Copyright (C) 2009 emlix GmbH, Oskar Schirmer <oskar@scara.com>
6323dd2c3STrent Piepho * Copyright (C) 2019 Trent Piepho <tpiepho@gmail.com>
72c64e9cbSAndy Shevchenko *
82c64e9cbSAndy Shevchenko * helper functions when coping with rational numbers
92c64e9cbSAndy Shevchenko */
102c64e9cbSAndy Shevchenko
112c64e9cbSAndy Shevchenko #include <linux/rational.h>
122c64e9cbSAndy Shevchenko #include <linux/compiler.h>
132c64e9cbSAndy Shevchenko #include <linux/export.h>
14b296a6d5SAndy Shevchenko #include <linux/minmax.h>
1565a0d3c1STrent Piepho #include <linux/limits.h>
16bcda5fd3SGeert Uytterhoeven #include <linux/module.h>
172c64e9cbSAndy Shevchenko
182c64e9cbSAndy Shevchenko /*
192c64e9cbSAndy Shevchenko * calculate best rational approximation for a given fraction
202c64e9cbSAndy Shevchenko * taking into account restricted register size, e.g. to find
212c64e9cbSAndy Shevchenko * appropriate values for a pll with 5 bit denominator and
222c64e9cbSAndy Shevchenko * 8 bit numerator register fields, trying to set up with a
232c64e9cbSAndy Shevchenko * frequency ratio of 3.1415, one would say:
242c64e9cbSAndy Shevchenko *
252c64e9cbSAndy Shevchenko * rational_best_approximation(31415, 10000,
262c64e9cbSAndy Shevchenko * (1 << 8) - 1, (1 << 5) - 1, &n, &d);
272c64e9cbSAndy Shevchenko *
282c64e9cbSAndy Shevchenko * you may look at given_numerator as a fixed point number,
292c64e9cbSAndy Shevchenko * with the fractional part size described in given_denominator.
302c64e9cbSAndy Shevchenko *
312c64e9cbSAndy Shevchenko * for theoretical background, see:
32d89775fcSAlexander A. Klimov * https://en.wikipedia.org/wiki/Continued_fraction
332c64e9cbSAndy Shevchenko */
342c64e9cbSAndy Shevchenko
rational_best_approximation(unsigned long given_numerator,unsigned long given_denominator,unsigned long max_numerator,unsigned long max_denominator,unsigned long * best_numerator,unsigned long * best_denominator)352c64e9cbSAndy Shevchenko void rational_best_approximation(
362c64e9cbSAndy Shevchenko unsigned long given_numerator, unsigned long given_denominator,
372c64e9cbSAndy Shevchenko unsigned long max_numerator, unsigned long max_denominator,
382c64e9cbSAndy Shevchenko unsigned long *best_numerator, unsigned long *best_denominator)
392c64e9cbSAndy Shevchenko {
40323dd2c3STrent Piepho /* n/d is the starting rational, which is continually
41323dd2c3STrent Piepho * decreased each iteration using the Euclidean algorithm.
42323dd2c3STrent Piepho *
43323dd2c3STrent Piepho * dp is the value of d from the prior iteration.
44323dd2c3STrent Piepho *
45323dd2c3STrent Piepho * n2/d2, n1/d1, and n0/d0 are our successively more accurate
46323dd2c3STrent Piepho * approximations of the rational. They are, respectively,
47323dd2c3STrent Piepho * the current, previous, and two prior iterations of it.
48323dd2c3STrent Piepho *
49323dd2c3STrent Piepho * a is current term of the continued fraction.
50323dd2c3STrent Piepho */
51323dd2c3STrent Piepho unsigned long n, d, n0, d0, n1, d1, n2, d2;
522c64e9cbSAndy Shevchenko n = given_numerator;
532c64e9cbSAndy Shevchenko d = given_denominator;
542c64e9cbSAndy Shevchenko n0 = d1 = 0;
552c64e9cbSAndy Shevchenko n1 = d0 = 1;
56323dd2c3STrent Piepho
572c64e9cbSAndy Shevchenko for (;;) {
58323dd2c3STrent Piepho unsigned long dp, a;
59323dd2c3STrent Piepho
602c64e9cbSAndy Shevchenko if (d == 0)
612c64e9cbSAndy Shevchenko break;
62323dd2c3STrent Piepho /* Find next term in continued fraction, 'a', via
63323dd2c3STrent Piepho * Euclidean algorithm.
64323dd2c3STrent Piepho */
65323dd2c3STrent Piepho dp = d;
662c64e9cbSAndy Shevchenko a = n / d;
672c64e9cbSAndy Shevchenko d = n % d;
68323dd2c3STrent Piepho n = dp;
69323dd2c3STrent Piepho
70323dd2c3STrent Piepho /* Calculate the current rational approximation (aka
71323dd2c3STrent Piepho * convergent), n2/d2, using the term just found and
72323dd2c3STrent Piepho * the two prior approximations.
73323dd2c3STrent Piepho */
74323dd2c3STrent Piepho n2 = n0 + a * n1;
75323dd2c3STrent Piepho d2 = d0 + a * d1;
76323dd2c3STrent Piepho
77323dd2c3STrent Piepho /* If the current convergent exceeds the maxes, then
78323dd2c3STrent Piepho * return either the previous convergent or the
79323dd2c3STrent Piepho * largest semi-convergent, the final term of which is
80323dd2c3STrent Piepho * found below as 't'.
81323dd2c3STrent Piepho */
82323dd2c3STrent Piepho if ((n2 > max_numerator) || (d2 > max_denominator)) {
8365a0d3c1STrent Piepho unsigned long t = ULONG_MAX;
84323dd2c3STrent Piepho
8565a0d3c1STrent Piepho if (d1)
8665a0d3c1STrent Piepho t = (max_denominator - d0) / d1;
8765a0d3c1STrent Piepho if (n1)
8865a0d3c1STrent Piepho t = min(t, (max_numerator - n0) / n1);
8965a0d3c1STrent Piepho
9065a0d3c1STrent Piepho /* This tests if the semi-convergent is closer than the previous
9165a0d3c1STrent Piepho * convergent. If d1 is zero there is no previous convergent as this
9265a0d3c1STrent Piepho * is the 1st iteration, so always choose the semi-convergent.
93323dd2c3STrent Piepho */
9465a0d3c1STrent Piepho if (!d1 || 2u * t > a || (2u * t == a && d0 * dp > d1 * d)) {
95323dd2c3STrent Piepho n1 = n0 + t * n1;
96323dd2c3STrent Piepho d1 = d0 + t * d1;
97323dd2c3STrent Piepho }
98323dd2c3STrent Piepho break;
99323dd2c3STrent Piepho }
1002c64e9cbSAndy Shevchenko n0 = n1;
101323dd2c3STrent Piepho n1 = n2;
1022c64e9cbSAndy Shevchenko d0 = d1;
103323dd2c3STrent Piepho d1 = d2;
1042c64e9cbSAndy Shevchenko }
1052c64e9cbSAndy Shevchenko *best_numerator = n1;
1062c64e9cbSAndy Shevchenko *best_denominator = d1;
1072c64e9cbSAndy Shevchenko }
1082c64e9cbSAndy Shevchenko
1092c64e9cbSAndy Shevchenko EXPORT_SYMBOL(rational_best_approximation);
110bcda5fd3SGeert Uytterhoeven
111*8547d115SJeff Johnson MODULE_DESCRIPTION("Rational fraction support library");
112bcda5fd3SGeert Uytterhoeven MODULE_LICENSE("GPL v2");
113