2017-02-07 9 views
1

ほとんどのデータ型ではテールコールを最適化できるテンプレート化されたコードがいくつかあります。コードはPOW()なぜboost :: multiprecision :: cpp_intを使ってテールコールの最適化に影響を与えるのですか

template<typename T, typename U> 
void powRecurse(T& x, U& y, T& acc) 
{ 
    if(y == 0) { 
     acc = Identity<T>; 
     return; 
    } 
    if(y == 1) { 
     acc = acc * x; 
     return; 
    } 
    if(y % 2 == 1) { 
     acc = acc * x; 
     y = y - 1; 
    } 
    x = x*x; 
    y = y/2; 
    powRecurse<T, U>(x, y, acc); 
} 

template<typename T, typename U> 
T tailPow(T x, U y) 
{ 
    T rv = Identity<T>; 
    powRecurse<T, U>(x, y, rv); 
    return rv; 
} 

を実装し、パラメータTの種類は、私が試したいずれかの種類が尾がパラメータ場合は、パラメータU.のための右の種類を最適化呼び出すことができ、何の末尾呼び出しの最適化に影響を与えていないようですUはuint64_tです。コンパイラはtail呼び出しを最適化できます。 boost :: multiprecision :: cpp_intの場合、コンパイラはtail呼び出しを最適化しません。

また、両方のtail呼び出しを最適化するint型のクラスとテンプレートラッパーでuint64_tをラップしようとしました。

テールコールが最適化されない理由はありますか?明らかにこれをループすることができますが、ここでは言語やコンパイラの問題を理解しようとしています。

+1

明白な、おそらく役に立たないコメント:コンパイラが最適化には義務を持っていないと、彼らは、私の知る限りでの集まりですヒューリスティックなので、 'cpp_int'が"十分に大きい "場合、コンパイラは末尾の再帰がそれに値するものではないと考えるかもしれません。それは非常に興味深いのですが、gcc(または他のコンパイラの)内部については十分な知識がなければ答えられるとは思えません。 – yeputons

+0

@yeputonsありがとう、ほとんど私はそれを不可能にする何かcpp_intにないと確信していません。一方、テールコールの最適化が悪化するケースは想像できませんが、インライン化後の関数の長さと最適化の可能性を識別できないアナライザが問題であることは想像できます。 –

答えて

1

レイジー評価は、すべての「再帰的」関数呼び出しが実際には異なる関数テンプレートのインスタンス化であることを意味します。

ここで同様の議論:

あなたはそれを期待して、あなたは怠惰な評価のテンプレート式のオプトアウトして、すべてのテールコル実装の詳細を持つことができます(リンクに記載されているboost::multiprecision::et_off)、コードサイズの縮小と認識されたTCO最適化が実際にはであることがパフォーマンスの向上につながることを確認してください。実際には

は、特定のアルゴリズムは、可逆操作などを並べ替え、共通部分式をスキップすることができる式テンプレートの恩恵を受ける

+0

私は見る!私はこれも、もともと私が渡した引数のいくつかとタイプの不一致を避けるために、関数呼び出しにテンプレートパラメータを指定しなければならなかったのかもしれないと思います。 –

+0

はい。あるいは、渡す前に引数を明示的にキャストすることもできます。 Boost Multiprecisionを使用しているユーザーにとっては、一般的な驚きです。私は彼らが文書で「T a、b; auto c = a + b; 'あなたの祖父のC++タイプのように 'c'のタイプを意味しません。 – sehe

+0

これは問題ではありませんが、ファクター。 –

関連する問題