C语言中的编译时LCM / GCD
时间:2020-03-05 18:57:01 来源:igfitidea点击:
有谁知道一种在编译时计算C中至少两个数字的LCM(最小公倍数)和/或者GCD(最大公分母)的机制(不是C ++,我知道那里有模板魔术)?
我通常使用GCC并回想一下,当所有输入都已知时(例如:sin,cos等),它可以在编译时计算某些值。
我正在寻找如何在GCC中执行此操作(最好采用其他编译器可以处理的方式),并希望在Visual Studio中可以使用相同的机制。
解决方案
回答
我想通了...
#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等)。
我希望这有帮助!
回答
我意识到我们只对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。
回答
部分基于凯文(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)
注意即使将其终止也将其扩展得太大,因为编译器必须在评估之前完全插入所有内容。