annotate lib/gcd.c @ 9084:2932e92d6e31

* lib/version-etc.c (version_etc_va): Default to GPLv3+. * NEWS: Document this change.
author Eric Blake <ebb9@byu.net>
date Tue, 10 Jul 2007 12:22:36 +0000
parents 7a37f7479e2a
children bbbbbf4cd1c5
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
3967
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
1 /* Arithmetic.
6763
16c1945e9422 Make generic.
Bruno Haible <bruno@clisp.org>
parents: 5848
diff changeset
2 Copyright (C) 2001-2002, 2006 Free Software Foundation, Inc.
3968
fd036b5fd367 Change argument type to 'unsigned long'.
Bruno Haible <bruno@clisp.org>
parents: 3967
diff changeset
3 Written by Bruno Haible <bruno@clisp.org>, 2001.
3967
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
4
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
5 This program is free software; you can redistribute it and/or modify
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
6 it under the terms of the GNU General Public License as published by
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
7 the Free Software Foundation; either version 2, or (at your option)
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
8 any later version.
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
9
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
10 This program is distributed in the hope that it will be useful,
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
13 GNU General Public License for more details.
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
14
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
15 You should have received a copy of the GNU General Public License
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
16 along with this program; if not, write to the Free Software Foundation,
5848
a48fb0e98c8c *** empty log message ***
Paul Eggert <eggert@cs.ucla.edu>
parents: 3977
diff changeset
17 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
3967
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
18
7472
7a37f7479e2a Make it possible to #define gcd to an alias.
Bruno Haible <bruno@clisp.org>
parents: 6763
diff changeset
19 #include <config.h>
7a37f7479e2a Make it possible to #define gcd to an alias.
Bruno Haible <bruno@clisp.org>
parents: 6763
diff changeset
20
6763
16c1945e9422 Make generic.
Bruno Haible <bruno@clisp.org>
parents: 5848
diff changeset
21 /* This file can also be used to define gcd functions for other unsigned
16c1945e9422 Make generic.
Bruno Haible <bruno@clisp.org>
parents: 5848
diff changeset
22 types, such as 'unsigned long long' or 'uintmax_t'. */
16c1945e9422 Make generic.
Bruno Haible <bruno@clisp.org>
parents: 5848
diff changeset
23 #ifndef WORD_T
3967
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
24 /* Specification. */
6763
16c1945e9422 Make generic.
Bruno Haible <bruno@clisp.org>
parents: 5848
diff changeset
25 # include "gcd.h"
16c1945e9422 Make generic.
Bruno Haible <bruno@clisp.org>
parents: 5848
diff changeset
26 # define WORD_T unsigned long
16c1945e9422 Make generic.
Bruno Haible <bruno@clisp.org>
parents: 5848
diff changeset
27 # define GCD gcd
16c1945e9422 Make generic.
Bruno Haible <bruno@clisp.org>
parents: 5848
diff changeset
28 #endif
3967
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
29
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
30 #include <stdlib.h>
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
31
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
32 /* Return the greatest common divisor of a > 0 and b > 0. */
6763
16c1945e9422 Make generic.
Bruno Haible <bruno@clisp.org>
parents: 5848
diff changeset
33 WORD_T
16c1945e9422 Make generic.
Bruno Haible <bruno@clisp.org>
parents: 5848
diff changeset
34 GCD (WORD_T a, WORD_T b)
3967
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
35 {
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
36 /* Why no division, as in Euclid's algorithm? Because in Euclid's algorithm
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
37 the division result floor(a/b) or floor(b/a) is very often = 1 or = 2,
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
38 and nearly always < 8. A sequence of a few subtractions and tests is
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
39 faster than a division. */
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
40 /* Why not Euclid's algorithm? Because the two integers can be shifted by 1
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
41 bit in a single instruction, and the algorithm uses fewer variables than
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
42 Euclid's algorithm. */
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
43
6763
16c1945e9422 Make generic.
Bruno Haible <bruno@clisp.org>
parents: 5848
diff changeset
44 WORD_T c = a | b;
3967
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
45 c = c ^ (c - 1);
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
46 /* c = largest power of 2 that divides a and b. */
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
47
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
48 if (a & c)
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
49 {
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
50 if (b & c)
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
51 goto odd_odd;
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
52 else
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
53 goto odd_even;
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
54 }
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
55 else
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
56 {
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
57 if (b & c)
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
58 goto even_odd;
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
59 else
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
60 abort ();
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
61 }
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
62
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
63 for (;;)
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
64 {
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
65 odd_odd: /* a/c and b/c both odd */
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
66 if (a == b)
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
67 break;
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
68 if (a > b)
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
69 {
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
70 a = a - b;
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
71 even_odd: /* a/c even, b/c odd */
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
72 do
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
73 a = a >> 1;
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
74 while ((a & c) == 0);
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
75 }
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
76 else
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
77 {
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
78 b = b - a;
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
79 odd_even: /* a/c odd, b/c even */
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
80 do
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
81 b = b >> 1;
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
82 while ((b & c) == 0);
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
83 }
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
84 }
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
85
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
86 /* a = b */
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
87 return a;
e8562282a2d0 Greatest common divisor.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
88 }