18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * rational fractions
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2009 emlix GmbH, Oskar Schirmer <oskar@scara.com>
68c2ecf20Sopenharmony_ci * Copyright (C) 2019 Trent Piepho <tpiepho@gmail.com>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * helper functions when coping with rational numbers
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/rational.h>
128c2ecf20Sopenharmony_ci#include <linux/compiler.h>
138c2ecf20Sopenharmony_ci#include <linux/export.h>
148c2ecf20Sopenharmony_ci#include <linux/minmax.h>
158c2ecf20Sopenharmony_ci#include <linux/limits.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/*
188c2ecf20Sopenharmony_ci * calculate best rational approximation for a given fraction
198c2ecf20Sopenharmony_ci * taking into account restricted register size, e.g. to find
208c2ecf20Sopenharmony_ci * appropriate values for a pll with 5 bit denominator and
218c2ecf20Sopenharmony_ci * 8 bit numerator register fields, trying to set up with a
228c2ecf20Sopenharmony_ci * frequency ratio of 3.1415, one would say:
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci * rational_best_approximation(31415, 10000,
258c2ecf20Sopenharmony_ci *		(1 << 8) - 1, (1 << 5) - 1, &n, &d);
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci * you may look at given_numerator as a fixed point number,
288c2ecf20Sopenharmony_ci * with the fractional part size described in given_denominator.
298c2ecf20Sopenharmony_ci *
308c2ecf20Sopenharmony_ci * for theoretical background, see:
318c2ecf20Sopenharmony_ci * https://en.wikipedia.org/wiki/Continued_fraction
328c2ecf20Sopenharmony_ci */
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_civoid rational_best_approximation(
358c2ecf20Sopenharmony_ci	unsigned long given_numerator, unsigned long given_denominator,
368c2ecf20Sopenharmony_ci	unsigned long max_numerator, unsigned long max_denominator,
378c2ecf20Sopenharmony_ci	unsigned long *best_numerator, unsigned long *best_denominator)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	/* n/d is the starting rational, which is continually
408c2ecf20Sopenharmony_ci	 * decreased each iteration using the Euclidean algorithm.
418c2ecf20Sopenharmony_ci	 *
428c2ecf20Sopenharmony_ci	 * dp is the value of d from the prior iteration.
438c2ecf20Sopenharmony_ci	 *
448c2ecf20Sopenharmony_ci	 * n2/d2, n1/d1, and n0/d0 are our successively more accurate
458c2ecf20Sopenharmony_ci	 * approximations of the rational.  They are, respectively,
468c2ecf20Sopenharmony_ci	 * the current, previous, and two prior iterations of it.
478c2ecf20Sopenharmony_ci	 *
488c2ecf20Sopenharmony_ci	 * a is current term of the continued fraction.
498c2ecf20Sopenharmony_ci	 */
508c2ecf20Sopenharmony_ci	unsigned long n, d, n0, d0, n1, d1, n2, d2;
518c2ecf20Sopenharmony_ci	n = given_numerator;
528c2ecf20Sopenharmony_ci	d = given_denominator;
538c2ecf20Sopenharmony_ci	n0 = d1 = 0;
548c2ecf20Sopenharmony_ci	n1 = d0 = 1;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	for (;;) {
578c2ecf20Sopenharmony_ci		unsigned long dp, a;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci		if (d == 0)
608c2ecf20Sopenharmony_ci			break;
618c2ecf20Sopenharmony_ci		/* Find next term in continued fraction, 'a', via
628c2ecf20Sopenharmony_ci		 * Euclidean algorithm.
638c2ecf20Sopenharmony_ci		 */
648c2ecf20Sopenharmony_ci		dp = d;
658c2ecf20Sopenharmony_ci		a = n / d;
668c2ecf20Sopenharmony_ci		d = n % d;
678c2ecf20Sopenharmony_ci		n = dp;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci		/* Calculate the current rational approximation (aka
708c2ecf20Sopenharmony_ci		 * convergent), n2/d2, using the term just found and
718c2ecf20Sopenharmony_ci		 * the two prior approximations.
728c2ecf20Sopenharmony_ci		 */
738c2ecf20Sopenharmony_ci		n2 = n0 + a * n1;
748c2ecf20Sopenharmony_ci		d2 = d0 + a * d1;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci		/* If the current convergent exceeds the maxes, then
778c2ecf20Sopenharmony_ci		 * return either the previous convergent or the
788c2ecf20Sopenharmony_ci		 * largest semi-convergent, the final term of which is
798c2ecf20Sopenharmony_ci		 * found below as 't'.
808c2ecf20Sopenharmony_ci		 */
818c2ecf20Sopenharmony_ci		if ((n2 > max_numerator) || (d2 > max_denominator)) {
828c2ecf20Sopenharmony_ci			unsigned long t = ULONG_MAX;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci			if (d1)
858c2ecf20Sopenharmony_ci				t = (max_denominator - d0) / d1;
868c2ecf20Sopenharmony_ci			if (n1)
878c2ecf20Sopenharmony_ci				t = min(t, (max_numerator - n0) / n1);
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci			/* This tests if the semi-convergent is closer than the previous
908c2ecf20Sopenharmony_ci			 * convergent.  If d1 is zero there is no previous convergent as this
918c2ecf20Sopenharmony_ci			 * is the 1st iteration, so always choose the semi-convergent.
928c2ecf20Sopenharmony_ci			 */
938c2ecf20Sopenharmony_ci			if (!d1 || 2u * t > a || (2u * t == a && d0 * dp > d1 * d)) {
948c2ecf20Sopenharmony_ci				n1 = n0 + t * n1;
958c2ecf20Sopenharmony_ci				d1 = d0 + t * d1;
968c2ecf20Sopenharmony_ci			}
978c2ecf20Sopenharmony_ci			break;
988c2ecf20Sopenharmony_ci		}
998c2ecf20Sopenharmony_ci		n0 = n1;
1008c2ecf20Sopenharmony_ci		n1 = n2;
1018c2ecf20Sopenharmony_ci		d0 = d1;
1028c2ecf20Sopenharmony_ci		d1 = d2;
1038c2ecf20Sopenharmony_ci	}
1048c2ecf20Sopenharmony_ci	*best_numerator = n1;
1058c2ecf20Sopenharmony_ci	*best_denominator = d1;
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rational_best_approximation);
109