3

Cで少なくとも2つの数値のLCM(最小公倍数)および/またはGCD(最大公約数)をコンパイル時に計算するメカニズムを知っている人はいますか(C++ ではなく、テンプレートマジックが利用できることを知っています)?

私は通常GCCを使用しますが、すべての入力が既知の場合 (例: sin、cos など)、コンパイル時に特定の値を計算できることを思い出してください。

GCCでこれを行う方法を探しています(できれば他のコンパイラが処理できる方法で)、同じメカニズムがVisual Studioで機能することを願っています。

4

4 に答える 4

6

やっぱり分かった...

#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 など) を含める必要がある場合があることに注意してください。

これが役立つことを願っています!

于 2008-09-16T20:37:03.450 に答える
2

ケビンの答えに部分的に基づいて、定数値の場合はコンパイル時のエラーが発生し、それ以外の場合は実行時エラーが発生するマクロシーケンスを次に示します。

失敗が許されない場合は、非コンパイル時関数を取り込むように構成することもできます。

#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)

コンパイラは評価する前にすべてを完全にプラグインする必要があるため、これが早期に終了したとしても、これを大きくしすぎることに注意してください。

于 2008-09-17T01:01:38.413 に答える
1

あなたが 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%確実ではありません。

于 2008-09-16T22:04:14.050 に答える