有没有人知道在编译时计算 C 中至少两个数字的LCM(最小公倍数)和/或GCD(最大公分母)的机制(不是C ++ ,我知道那里有模板魔法吗?
我通常使用 GCC 并回想一下,当所有输入都已知时,它可以在编译时计算某些值(例如:sin,cos等等)。
我正在寻找如何在 GCC 中执行此操作(最好以其他编译器可以处理的方式),并希望在Visual Studio中使用相同的机制。
答案 0 :(得分:5)
我事后想通了......
#define GCD(a,b) ((a>=b)*GCD_1(a,b)+(a<b)*GCD_1(b,a))
#define GCD_1(a,b) ((((!(b)))*(a)) + (!!(b))*GCD_2((b), (a)%((b)+!(b))))
#define GCD_2(a,b) ((((!(b)))*(a)) + (!!(b))*GCD_3((b), (a)%((b)+!(b))))
#define GCD_3(a,b) ((((!(b)))*(a)) + (!!(b))*GCD_4((b), (a)%((b)+!(b))))
#define GCD_4(a,b) ((((!(b)))*(a)) + (!!(b))*GCD_5((b), (a)%((b)+!(b))))
#define GCD_5(a,b) ((((!(b)))*(a)) + (!!(b))*GCD_6((b), (a)%((b)+!(b))))
#define GCD_6(a,b) ((((!(b)))*(a)) + (!!(b))*GCD_7((b), (a)%((b)+!(b))))
#define GCD_7(a,b) ((((!(b)))*(a)) + (!!(b))*GCD_8((b), (a)%((b)+!(b))))
#define GCD_8(a,b) ((((!(b)))*(a)) + (!!(b))*GCD_last((b), (a)%((b)+!(b))))
#define GCD_last(a,b) (a)
#define LCM(a,b) (((a)*(b))/GCD(a,b))
int main()
{
printf("%d, %d\n", GCD(21,6), LCM(21,6));
return 0;
}
注意,根据整数的大小,您可能需要包含更多中间步骤(即GCD_9,GCD_10等......)。
我希望这有帮助!
答案 1 :(得分:1)
部分基于Kevin的回答,这里是一个宏序列,否则会导致常量值和运行时错误的编译时失败。
如果失败不是一个选项,它也可以配置为引入非编译时功能。
#define GCD(a,b) ( ((a) > (b)) ? ( GCD_1((a), (b)) ) : ( GCD_1((b), (a)) ) )
#define GCD_1(a,b) ( ((b) == 0) ? (a) : GCD_2((b), (a) % (b) ) )
#define GCD_2(a,b) ( ((b) == 0) ? (a) : GCD_3((b), (a) % (b) ) )
#define GCD_3(a,b) ( ((b) == 0) ? (a) : GCD_4((b), (a) % (b) ) )
#define GCD_4(a,b) ( ((b) == 0) ? (a) : GCD_5((b), (a) % (b) ) )
#define GCD_5(a,b) ( ((b) == 0) ? (a) : GCD_6((b), (a) % (b) ) )
#define GCD_6(a,b) ( ((b) == 0) ? (a) : GCD_7((b), (a) % (b) ) )
#define GCD_7(a,b) ( ((b) == 0) ? (a) : GCD_8((b), (a) % (b) ) )
#define GCD_8(a,b) ( ((b) == 0) ? (a) : GCD_9((b), (a) % (b) ) )
#define GCD_9(a,b) (assert(0),-1)
请注意扩展它太大,即使它会提前终止,因为编译器必须在评估之前完全插入所有内容。
答案 2 :(得分:0)
我意识到你唯一对C实现感兴趣,但我认为无论如何我都会评论C ++和模板元编程。我不完全相信它在C ++中是可能的,因为你需要定义良好的初始条件才能终止递归扩展。
template<int A, int B>
struct GCD {
enum { value = GCD<B, A % B>::value };
};
/*
Because GCD terminates when only one of the values is zero it is impossible to define a base condition to satisfy all GCD<N, 0>::value conditions
*/
template<>
struct GCD<A, 0> { // This is obviously not legal
enum { value = A };
};
int main(void)
{
::printf("gcd(%d, %d) = %d", 7, 35, GCD<7, 35>::value);
}
这可能适用于C ++ 0x,但不是%100肯定。