-
Notifications
You must be signed in to change notification settings - Fork 0
/
GcdBinary.cpp
43 lines (40 loc) · 1.13 KB
/
GcdBinary.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#if defined(_MSC_VER) && defined(_WIN64)
#include <intrin.h>
#define CTZ(x) ([&] () {uint64_t _r = 0; _BitScanForward64(&_r,(x)); return _r;} ())
#elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3)))
#define CTZ(x) __builtin_ctzll((uint64_t)(x))
#else
#include "bitScanForward.h"
#define CTZ(x) bitScanForward((x))
#endif
// https://lemire.me/blog/2013/12/26/fastest-way-to-compute-the-greatest-common-divisor/
//
// References:
//
// https://gist.github.com/cslarsen/1635213
// https://chessprogramming.wikispaces.com/BitScan
// http://chessprogramming.wikispaces.com/De+Bruijn+Sequence+Generator
// https://en.wikipedia.org/wiki/Find_first_set#CTZ
// https://en.wikipedia.org/wiki/De_Bruijn_sequence
// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogDeBruijn
//
uint64_t gcd_binary(uint64_t u, uint64_t v) {
uint64_t shift;
if (u == 0) return v;
if (v == 0) return u;
shift = CTZ(u | v);
u >>= CTZ(u);
do {
v >>= CTZ(v);
if (u > v) {
uint64_t t = v;
v = u;
u = t;
}
v = v - u;
} while (v != 0);
return u << shift;
}