Something went wrong. Try again.
(I'm so sorry!) Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889// SPDX-License-Identifier: GPL-2.0-only#include <linux/kernel.h>#include <linux/gcd.h>#include <linux/export.h>
/* * This implements the binary GCD algorithm. (Often attributed to Stein, * but as Knuth has noted, appears in a first-century Chinese math text.) * * This is faster than the division-based algorithm even on x86, which * has decent hardware division. */
DEFINE_STATIC_KEY_TRUE(efficient_ffs_key);
#if !defined(CONFIG_CPU_NO_EFFICIENT_FFS)
/* If __ffs is available, the even/odd algorithm benchmarks slower. */
static unsigned long binary_gcd(unsigned long a, unsigned long b){ unsigned long r = a | b;
b >>= __ffs(b); if (b == 1) return r & -r;
for (;;) { a >>= __ffs(a); if (a == 1) return r & -r; if (a == b) return a << __ffs(r);
if (a < b) swap(a, b); a -= b; }}
#endif
/* If normalization is done by loops, the even/odd algorithm is a win. */
/** * gcd - calculate and return the greatest common divisor of 2 unsigned longs * @a: first value * @b: second value */unsigned long gcd(unsigned long a, unsigned long b){ unsigned long r = a | b;
if (!a || !b) return r;
#if !defined(CONFIG_CPU_NO_EFFICIENT_FFS) if (static_branch_likely(&efficient_ffs_key)) return binary_gcd(a, b);#endif
/* Isolate lsbit of r */ r &= -r;
while (!(b & r)) b >>= 1; if (b == r) return r;
for (;;) { while (!(a & r)) a >>= 1; if (a == r) return r; if (a == b) return a;
if (a < b) swap(a, b); a -= b; a >>= 1; if (a & r) a += b; a >>= 1; }}
EXPORT_SYMBOL_GPL(gcd);