xref: /linux/lib/math/gcd.c (revision 457c89965399115e5cd8bf38f9c597293405703d)
1*457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
22c64e9cbSAndy Shevchenko #include <linux/kernel.h>
32c64e9cbSAndy Shevchenko #include <linux/gcd.h>
42c64e9cbSAndy Shevchenko #include <linux/export.h>
52c64e9cbSAndy Shevchenko 
62c64e9cbSAndy Shevchenko /*
72c64e9cbSAndy Shevchenko  * This implements the binary GCD algorithm. (Often attributed to Stein,
82c64e9cbSAndy Shevchenko  * but as Knuth has noted, appears in a first-century Chinese math text.)
92c64e9cbSAndy Shevchenko  *
102c64e9cbSAndy Shevchenko  * This is faster than the division-based algorithm even on x86, which
112c64e9cbSAndy Shevchenko  * has decent hardware division.
122c64e9cbSAndy Shevchenko  */
132c64e9cbSAndy Shevchenko 
142c64e9cbSAndy Shevchenko #if !defined(CONFIG_CPU_NO_EFFICIENT_FFS)
152c64e9cbSAndy Shevchenko 
162c64e9cbSAndy Shevchenko /* If __ffs is available, the even/odd algorithm benchmarks slower. */
172c64e9cbSAndy Shevchenko 
182c64e9cbSAndy Shevchenko /**
192c64e9cbSAndy Shevchenko  * gcd - calculate and return the greatest common divisor of 2 unsigned longs
202c64e9cbSAndy Shevchenko  * @a: first value
212c64e9cbSAndy Shevchenko  * @b: second value
222c64e9cbSAndy Shevchenko  */
232c64e9cbSAndy Shevchenko unsigned long gcd(unsigned long a, unsigned long b)
242c64e9cbSAndy Shevchenko {
252c64e9cbSAndy Shevchenko 	unsigned long r = a | b;
262c64e9cbSAndy Shevchenko 
272c64e9cbSAndy Shevchenko 	if (!a || !b)
282c64e9cbSAndy Shevchenko 		return r;
292c64e9cbSAndy Shevchenko 
302c64e9cbSAndy Shevchenko 	b >>= __ffs(b);
312c64e9cbSAndy Shevchenko 	if (b == 1)
322c64e9cbSAndy Shevchenko 		return r & -r;
332c64e9cbSAndy Shevchenko 
342c64e9cbSAndy Shevchenko 	for (;;) {
352c64e9cbSAndy Shevchenko 		a >>= __ffs(a);
362c64e9cbSAndy Shevchenko 		if (a == 1)
372c64e9cbSAndy Shevchenko 			return r & -r;
382c64e9cbSAndy Shevchenko 		if (a == b)
392c64e9cbSAndy Shevchenko 			return a << __ffs(r);
402c64e9cbSAndy Shevchenko 
412c64e9cbSAndy Shevchenko 		if (a < b)
422c64e9cbSAndy Shevchenko 			swap(a, b);
432c64e9cbSAndy Shevchenko 		a -= b;
442c64e9cbSAndy Shevchenko 	}
452c64e9cbSAndy Shevchenko }
462c64e9cbSAndy Shevchenko 
472c64e9cbSAndy Shevchenko #else
482c64e9cbSAndy Shevchenko 
492c64e9cbSAndy Shevchenko /* If normalization is done by loops, the even/odd algorithm is a win. */
502c64e9cbSAndy Shevchenko unsigned long gcd(unsigned long a, unsigned long b)
512c64e9cbSAndy Shevchenko {
522c64e9cbSAndy Shevchenko 	unsigned long r = a | b;
532c64e9cbSAndy Shevchenko 
542c64e9cbSAndy Shevchenko 	if (!a || !b)
552c64e9cbSAndy Shevchenko 		return r;
562c64e9cbSAndy Shevchenko 
572c64e9cbSAndy Shevchenko 	/* Isolate lsbit of r */
582c64e9cbSAndy Shevchenko 	r &= -r;
592c64e9cbSAndy Shevchenko 
602c64e9cbSAndy Shevchenko 	while (!(b & r))
612c64e9cbSAndy Shevchenko 		b >>= 1;
622c64e9cbSAndy Shevchenko 	if (b == r)
632c64e9cbSAndy Shevchenko 		return r;
642c64e9cbSAndy Shevchenko 
652c64e9cbSAndy Shevchenko 	for (;;) {
662c64e9cbSAndy Shevchenko 		while (!(a & r))
672c64e9cbSAndy Shevchenko 			a >>= 1;
682c64e9cbSAndy Shevchenko 		if (a == r)
692c64e9cbSAndy Shevchenko 			return r;
702c64e9cbSAndy Shevchenko 		if (a == b)
712c64e9cbSAndy Shevchenko 			return a;
722c64e9cbSAndy Shevchenko 
732c64e9cbSAndy Shevchenko 		if (a < b)
742c64e9cbSAndy Shevchenko 			swap(a, b);
752c64e9cbSAndy Shevchenko 		a -= b;
762c64e9cbSAndy Shevchenko 		a >>= 1;
772c64e9cbSAndy Shevchenko 		if (a & r)
782c64e9cbSAndy Shevchenko 			a += b;
792c64e9cbSAndy Shevchenko 		a >>= 1;
802c64e9cbSAndy Shevchenko 	}
812c64e9cbSAndy Shevchenko }
822c64e9cbSAndy Shevchenko 
832c64e9cbSAndy Shevchenko #endif
842c64e9cbSAndy Shevchenko 
852c64e9cbSAndy Shevchenko EXPORT_SYMBOL_GPL(gcd);
86