Blame view

lib/rational.c 1.55 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
8759ef32d   Oskar Schirmer   lib: isolate rati...
2
3
4
  /*
   * rational fractions
   *
6684b5729   Oskar Schirmer   lib: Change mail ...
5
   * Copyright (C) 2009 emlix GmbH, Oskar Schirmer <oskar@scara.com>
8759ef32d   Oskar Schirmer   lib: isolate rati...
6
7
8
9
10
   *
   * helper functions when coping with rational numbers
   */
  
  #include <linux/rational.h>
8bc3bcc93   Paul Gortmaker   lib: reduce the u...
11
12
  #include <linux/compiler.h>
  #include <linux/export.h>
8759ef32d   Oskar Schirmer   lib: isolate rati...
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
  
  /*
   * calculate best rational approximation for a given fraction
   * taking into account restricted register size, e.g. to find
   * appropriate values for a pll with 5 bit denominator and
   * 8 bit numerator register fields, trying to set up with a
   * frequency ratio of 3.1415, one would say:
   *
   * rational_best_approximation(31415, 10000,
   *		(1 << 8) - 1, (1 << 5) - 1, &n, &d);
   *
   * you may look at given_numerator as a fixed point number,
   * with the fractional part size described in given_denominator.
   *
   * for theoretical background, see:
   * http://en.wikipedia.org/wiki/Continued_fraction
   */
  
  void 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)
  {
  	unsigned long n, d, n0, d0, n1, d1;
  	n = given_numerator;
  	d = given_denominator;
  	n0 = d1 = 0;
  	n1 = d0 = 1;
  	for (;;) {
  		unsigned long t, a;
  		if ((n1 > max_numerator) || (d1 > max_denominator)) {
  			n1 = n0;
  			d1 = d0;
  			break;
  		}
  		if (d == 0)
  			break;
  		t = d;
  		a = n / d;
  		d = n % d;
  		n = t;
  		t = n0 + a * n1;
  		n0 = n1;
  		n1 = t;
  		t = d0 + a * d1;
  		d0 = d1;
  		d1 = t;
  	}
  	*best_numerator = n1;
  	*best_denominator = d1;
  }
  
  EXPORT_SYMBOL(rational_best_approximation);