gcd.c 1.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. #include <linux/kernel.h>
  2. #include <linux/gcd.h>
  3. #include <linux/export.h>
  4. /*
  5. * This implements the binary GCD algorithm. (Often attributed to Stein,
  6. * but as Knuth has noted, appears in a first-century Chinese math text.)
  7. *
  8. * This is faster than the division-based algorithm even on x86, which
  9. * has decent hardware division.
  10. */
  11. #if !defined(CONFIG_CPU_NO_EFFICIENT_FFS) && !defined(CPU_NO_EFFICIENT_FFS)
  12. /* If __ffs is available, the even/odd algorithm benchmarks slower. */
  13. unsigned long gcd(unsigned long a, unsigned long b)
  14. {
  15. unsigned long r = a | b;
  16. if (!a || !b)
  17. return r;
  18. b >>= __ffs(b);
  19. if (b == 1)
  20. return r & -r;
  21. for (;;) {
  22. a >>= __ffs(a);
  23. if (a == 1)
  24. return r & -r;
  25. if (a == b)
  26. return a << __ffs(r);
  27. if (a < b)
  28. swap(a, b);
  29. a -= b;
  30. }
  31. }
  32. #else
  33. /* If normalization is done by loops, the even/odd algorithm is a win. */
  34. unsigned long gcd(unsigned long a, unsigned long b)
  35. {
  36. unsigned long r = a | b;
  37. if (!a || !b)
  38. return r;
  39. /* Isolate lsbit of r */
  40. r &= -r;
  41. while (!(b & r))
  42. b >>= 1;
  43. if (b == r)
  44. return r;
  45. for (;;) {
  46. while (!(a & r))
  47. a >>= 1;
  48. if (a == r)
  49. return r;
  50. if (a == b)
  51. return a;
  52. if (a < b)
  53. swap(a, b);
  54. a -= b;
  55. a >>= 1;
  56. if (a & r)
  57. a += b;
  58. a >>= 1;
  59. }
  60. }
  61. #endif
  62. EXPORT_SYMBOL_GPL(gcd);