欧几里得算法
u,v都是偶数时 gcd(u, v) = 2gcd(u/2, v/2)
u,v只有一个偶数时,偶数u时 gcd(u, v) = gcd(u/2, v);偶数v时 gcd(u, v) = gcd(u, v/2)
u,v都是奇数时,u > v时 gcd(u, v) = gcd((u - v)/2, v); u < v时 gcd(u, v) = gcd(u, (v - u)/2)
Unsigned版本
/// <summary>
/// 计算<paramref name="a"/>和<paramref name="b"/>的最大公约数
/// </summary>
public static uint GreatestCommonDivisor(uint a, uint b)
{
if (a == 0) return b;
if (b == 0) return a;
var aZeros = a.NumberOfTrailingZeros();
var bZeros = b.NumberOfTrailingZeros();
a >>= aZeros;
b >>= bZeros;
var t = Math.Min(aZeros, bZeros);
while (a != b)
{
if (a > b)
{
a -= b;
a >>= a.NumberOfTrailingZeros();
}
else
{
b -= a;
b >>= b.NumberOfTrailingZeros();
}
}
return a << t;
}
NumberOfTrailingZeros用来计算二进制尾数0的个数
/// <summary>
/// <paramref name="n"/>二进制尾数0的个数
/// </summary>
public static int NumberOfTrailingZeros(this uint n)
{
if (n == 0) return 32;
var c = 31;
var t = n << 16; if (t != 0u) { c -= 16; n = t; }
t = n << 8; if (t != 0u) { c -= 8; n = t; }
t = n << 4; if (t != 0u) { c -= 4; n = t; }
t = n << 2; if (t != 0u) { c -= 2; n = t; }
t = n << 1; if (t != 0u) { c -= 1; }
return c;
}
Signed版本
/// <summary>
/// 计算<paramref name="a"/>和<paramref name="b"/>的最大公约数
/// </summary>
public static int GreatestCommonDivisor(int a, int b)
{
if (a == 0) return b;
if (b == 0) return a;
a = (a ^ (a >> 31)) - (a >> 31);//a = abs(a)
b = (b ^ (b >> 31)) - (b >> 31);//b = abs(b)
var aZeros = a.NumberOfTrailingZeros();
var bZeros = b.NumberOfTrailingZeros();
a >>= a.NumberOfTrailingZeros();
b >>= b.NumberOfTrailingZeros();
var t = Math.Min(aZeros, bZeros);
while (a != b)
{
if (a > b)
{
a -= b;
a >>= a.NumberOfTrailingZeros();
}
else
{
b -= a;
b >>= b.NumberOfTrailingZeros();
}
}
return a << t;
}
/// <summary>
/// <paramref name="n"/>二进制尾数0的个数
/// </summary>
public static int NumberOfTrailingZeros(this int n)
{
if (n == 0) return 32;
var c = 31;
var t = n << 16; if (t != 0) { c -= 16; n = t; }
t = n << 8; if (t != 0) { c -= 8; n = t; }
t = n << 4; if (t != 0) { c -= 4; n = t; }
t = n << 2; if (t != 0) { c -= 2; n = t; }
t = n << 1; if (t != 0) { c -= 1; }
return c;
}