アルゴリズムの複雑さをテストする必要がありますか?もしそうなら、どのように?


14

ソートされたリスト/配列の検索のような単純なものを実装しているとしましょう。関数(c#内)は次のようになります。

static int FindIndex(int[] sortedList, int i);

機能の面でこれを実装してテストすることもできますが、明らかな理由から、通常は線形検索や意図的に愚かなものよりもバイナリ検索を好むでしょう。

だから私の質問は次のとおりです。アルゴリズムの複雑さの観点からパフォーマンスを保証するテストを作成する必要がありますか?

私はこの質問の「あなたがすべき」部分の両側で議論を始めましたが、私はそれらを促すために私の議論なしで人々が言うことを見てみたいです。

「方法」に関しては、非常に興味深いものになります:)比較演算子をパラメーター化して、比較演算子が比較などをカウントするテストを持つことがわかります。しかし、あなたができるからといって...

他の誰かが(おそらく)これを考えましたか?ありがとう。


@steenhulthin-これをここで煮て、チェックしてみましょう。私はそこに行ったことがありませんでした。
サーペンター

ところで、いい質問です。+1
ラファエルコルッチ

回答:


13

アルゴリズムの複雑さは理論的な構成であり、鉛筆と紙で「テスト」するのが最適です。機械的に有効にテストすることはできません。

絶対パフォーマンス機械的にテストでき、有用な単体テストを作成できます。パフォーマンスが重要な場合は、しきい値を指定できます:「このクエリは10 6の数値で実行するのに50ミリ秒以内、10 7の数値で60ミリ秒以内に実行する」あなたはその可能のためのユニットテストを構築します。

エンドユーザーは、アルゴリズムが線形か対数かを気にしません。アプリに1年分のデータがある場合でも、UIがすぐに応答するかどうかを気にします。


これも私の本能です。しかし、私が考えたのは、パフォーマンスがフレームワークで保証されるときです。例:正しく思い出せば、stlにはアルゴリズムの複雑さに関する保証があります(ここではオフにできます)。
サーペンター

ライブラリが何らかの保証を提供しているからといって、ユニットテスト可能である必要があるというわけではありません。
svick

@Tobias Brick:何かをテストすることと何かを定義することは、2つの異なることです。
DeadMG

パフォーマンスを実証するのは難しいです。さまざまなパラメーターのサンプルポイントが多数含まれています。個々の機能が簡単な場合は簡単ですが、それを超えて...あなたの負荷、RAM、フロントバス速度、CPU、コア数、コンパイラーの攻撃性、レジストリの汚染度はすべて、特定の実行時間に影響しますサンプル。
ジョブ

3

このツールが単体テストに特に役立つかどうかはわかりませんが、ゴールドスミス、エイケン、およびウィルカーソンによる論文「経験的計算の複雑さ」では、コードをインスツルメントし、さまざまな入力のセットでの動的な挙動を経験的に検証する方法について説明しています漸近的な複雑さを導き出します。論文に記載されているプログラムはオープンソースであり、こちらから入手できます

お役に立てれば!


0

主なことは、ビッグデータで試してみて、時間がかかりすぎるかどうかを確認することです。

私のパフォーマンスチューニングの経験では、この例のように、あるアルゴリズムが(たとえば)O(n ^ 2)である場合、それがかかる時間の割合がレーダーに到達しない限り、問題ないことがあります。

ただし、1年に1回は見られないようなサイズのデータ​​セットが与えられると、そのアルゴリズムによって消費される合計時間の一部が壊滅的に支配的になる可能性があります。

テストでそれを実現できるなら、それは非常に良いことです。なぜなら、まるで実際の無限ループであるかのように、問題を見つけるのは非常に簡単だからです。


0

あなたがしたいのはユニットテストだとは思いません。

知る限り、単体テストは、コードが実行すべきことを確認するためだけのものであり、パフォーマンスに焦点を合わせていません。

ウィキペディアから:プログラムのすべてのエラーをキャッチするテストは期待できません。最も些細なプログラム以外のすべての実行パスを評価することは不可能です。同じことがユニットテストにも当てはまります。さらに、定義による単体テストでは、ユニット自体の機能のみがテストされます。したがって、統合エラーやより広範なシステムレベルのエラー(複数のユニット間で実行される機能、パフォーマンスなどの非機能テスト領域など)をキャッチしません。単体テストは、他のソフトウェアテストアクティビティと組み合わせて実行する必要があります。すべての形式のソフトウェアテストと同様に、単体テストではエラーの存在のみを表示できます。エラーがないことを示すことはできません。

パフォーマンスを測定する他の種類のツールとパターンがあります。私が今覚えていることの1つは、非機能要件に焦点を当てた受け入れテストです。

パフォーマンステスト(ストレステスト、負荷テストなどを使用)のような他のいくつかがあります。

また、いくつかのストレスツールとビルドツール(ant、自動ビルドスタジオ)を展開手順の一部として使用することもできます(これは私が行っていることです)。

簡単な答えはノーです。コードを単体テストするとき、それについて心配するべきではありません。


0

コンパレータを渡して、呼び出された回数を追跡できるようにすることは、固定入力(たとえばnew int[] { 1,2,3, ... , 1024 })で検索を行うときの比較回数が10未満にとどまることを確認するなどの単純な目的で機能します。アルゴリズムの動作方法に関する意図を明確にします。

ユニットテストは、アルゴリズムがO(log n)であることを確認する正しい方法ではないと思います。そのためには、大量のデータポイントが予想されるランタイムに適合するかどうかを判断するために、大量のランダムデータ生成、ある程度のカーブフィッティング、およびおそらく危険な統計が必要になります。(このアルゴリズムではおそらく実行可能ですが、並べ替えなどを開始すると、最悪のシナリオに繰り返しヒットすることが難しくなります)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.