(注:これは 言語弁護士 の質問を目的としています。特定の既存のコンパイラについては言及していません。 )
コンパイラがプログラムの時間計算量を低下させることができるのはいつですか?
これはどのような状況(もしあれば)で「観察可能な行動」と見なされますか、またその理由は何ですか?
(たとえば、コンパイラーは、多項式時間プログラムを指数時間プログラムに合法的に「削減」できますか?)
答えがCとC++、またはどちらかのバージョンで異なる場合は、違いを説明してください。
C標準には、プリミティブ演算やライブラリ関数のいずれについても、実際には時間計算量モデルがないため、コンパイラは、プログラムのセマンティクス(観察可能な動作)を保持するほとんどすべてのことを実行できます。
C++標準は、一部のライブラリ関数に対してのみ複雑さの保証を提供し、(17.5.1.4 [structure.specifications])と述べています。
ライブラリ句で指定された複雑さの要件は上限であり、より優れた複雑さの保証を提供する実装は要件を満たします。
コンパイラーはこれらの境界をより適切に保持します(そして、関数の多くはテンプレート化されている/インライン化されている可能性があるため、コンパイラーが関与します)が、境界はコンテナー内の要素の数に関するものであり、比較演算子との呼び出しの数を制限します。お気に入り。それ以外の場合、コンパイラーは自由に自由に実行できます。
コードのパフォーマンスは観察可能な動作とは見なされず、コンパイラーによってどちらの方向にも変更される可能性があります。実際には、実装の品質(QoI)の理由から、コンパイラーはプログラムを劣化させませんが、QoIがパフォーマンスではない場合があります。
コンパイラーは、適切なフラグを指定すると、デバッグ目的でビルドしているプログラムにインストルメンテーションを追加できます(これは、チェックされたイテレーターなどのライブラリー実装の場合によくあります)。
whenコンパイラがプログラムを劣化させるという単純な答えは、クライアントが要求したときと、実装者がコンパイラのユーザーを望まないときの2つであることに注意してください。
C標準の5.1.2.3は言う
この国際規格のセマンティック記述は、最適化の問題が無関係である抽象マシンの動作を記述しています。
C++標準には、1.9 [intro.execution]でも同様の表現があります。
両方の標準には、観察可能な動作の同じ定義があります。
準拠する実装の最小要件は次のとおりです。
—揮発性オブジェクトへのアクセスは、抽象マシンのルールに従って厳密に評価されます。
—プログラムの終了時に、ファイルに書き込まれるすべてのデータは、抽象セマンティクスに従ってプログラムを実行した場合の結果と同じでなければなりません。
—インタラクティブデバイスの入力および出力ダイナミクスは、7.21.3で指定されているように実行されるものとします。これらの要件の目的は、プログラムが入力を待機する前にプロンプトメッセージが実際に表示されるように、バッファなしまたは行バッファ付きの出力ができるだけ早く表示されるようにすることです。
これはプログラムの観察可能な動作です。
だから他のもの、例えばfor
ループのパフォーマンス、または非揮発性変数に対して実行された読み取り/書き込みの数は、監視可能とは見なされないため、コンパイラーに対応するパフォーマンス要件はありません。
コンパイラがコードのブロックを100回再評価したい場合(観察可能な副作用がなく、不揮発性変数の状態を変更するだけであると仮定)、毎回同じ結果が得られたことを確認します(宇宙の影響を受けません)。標準で許可される光線または障害のあるハードウェア)。
他の人は、標準がCランタイムの動作を制約せず、観察可能な動作のみを制約していると指摘しています。たとえば、Cを解釈したりJITコンパイルしたりできない理由はありません。
すべてのメモリセルが基盤となるシステムのリンクリストに格納されているC実装について考えてみます。ポインタは、このリンクリストへのインデックスになります。ランタイムがすべてのメモリアクセスでリンクリストを反復処理する必要があることを除いて、すべてのポインタ操作は通常どおり機能します。あらゆる種類の一般的なアルゴリズムは、たとえば一般的なnullで終了する文字列操作など、複雑さの点で突然Nの追加係数を取得します。