gcd.c 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  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. /**
  14. * gcd - calculate and return the greatest common divisor of 2 unsigned longs
  15. * @a: first value
  16. * @b: second value
  17. */
  18. unsigned long gcd(unsigned long a, unsigned long b)
  19. {
  20. unsigned long r = a | b;
  21. if (!a || !b)
  22. return r;
  23. b >>= __ffs(b);
  24. if (b == 1)
  25. return r & -r;
  26. for (;;) {
  27. a >>= __ffs(a);
  28. if (a == 1)
  29. return r & -r;
  30. if (a == b)
  31. return a << __ffs(r);
  32. if (a < b)
  33. swap(a, b);
  34. a -= b;
  35. }
  36. }
  37. #else
  38. /* If normalization is done by loops, the even/odd algorithm is a win. */
  39. unsigned long gcd(unsigned long a, unsigned long b)
  40. {
  41. unsigned long r = a | b;
  42. if (!a || !b)
  43. return r;
  44. /* Isolate lsbit of r */
  45. r &= -r;
  46. while (!(b & r))
  47. b >>= 1;
  48. if (b == r)
  49. return r;
  50. for (;;) {
  51. while (!(a & r))
  52. a >>= 1;
  53. if (a == r)
  54. return r;
  55. if (a == b)
  56. return a;
  57. if (a < b)
  58. swap(a, b);
  59. a -= b;
  60. a >>= 1;
  61. if (a & r)
  62. a += b;
  63. a >>= 1;
  64. }
  65. }
  66. #endif
  67. EXPORT_SYMBOL_GPL(gcd);