4

私は現在コード コントラクトをいじっていますが、コントラクト クラスの静的メソッドが条件の数学的表記法と競合するほど強力であるかどうかは完全にはわかりません。

単純な階乗法があるとしましょう

int Factorial(int n);

私は次の条件を表明します:

Precondition:
n >= 0

Postconditions:
Factorial(n) = 1, in case n = 0
Factorial(n) = n*(n-1)*...*1, in case n > 0

これらの条件は、Factial の動作を簡潔かつ明確な方法で明確に指定します。私の質問は、コード コントラクトを通じて表現できるかどうかです。

前提条件は簡単です:

Contract.Requires(n >= 0)

条件付き事後条件は、次を使用して表現できます。

if(n==0)
    Contract.Ensures(Contract.Result<int>() == 1);
if(n > 0)
    ...

しかし、ここで「if」ステートメントが必要な方法は好きではありません。前条件と後条件の単純なリストが読みにくくなるためです。私は私たちが何かを持っていることを望みました

Contract.Ensures(...).InCase(...);

最後になりましたが、数学に関する一般的な表記法であるこれを表現する方法がわかりません。

n*(n-1)*...*1

ある種のループが必要になると思いますが、これは実装全体をコピーします。そのような表記法を表現するスマートな方法はありますか?

前もって感謝します。

4

2 に答える 2

4

あなたが探しているのは、コード コントラクトではなく、ユニット テストです。

if n=0, then f(n) = 1典型的には、およびのようなチェックはif n=3, then f(n) = 6、単体テストとして表現する必要があるテスト ケースです。

あなたの場合、適切な事後条件は「結果は常に> = 1」のようなものになると思います。そして、それ以上のものはありません。

階乗クラスが次のようになっていると仮定します。

public class Factorial
{
    public int Compute(int n)
    {
        if (n == 0)
            return 1;

        return n * Compute(n - 1);
    }
}

NUnit フレームワークで記述された適切な単体テストは次のようになります。

[TestFixture]
public class FactorialTests
{
    [TestCase(0, 1)]
    [TestCase(1, 1)]
    [TestCase(2, 2)]
    [TestCase(7, 5040)]
    [TestCase(10, 3628800)]
    public void Compute_ReturnsCorrectResult(int n, int expectedResult)
    {
        var sut = new Factorial();

        Assert.AreEqual(expectedResult, sut.Compute(n));
    }
}

更新(コメントの後)

result >= 1 と記述しても、アルゴリズムが完全には指定されません。

Code Contract の仕事は、アルゴリズムを詳細に指定することではないと思います。アルゴリズムはメソッドによって指定されます。

コード コントラクトがメソッド自体のような複雑なロジックである場合、コード コントラクトが正しいチェックを実行することを確認するために、コード コントラクト コントラクトが必要になると思います。これは明らかに無限再帰につながります。

n*(n-1)*...*1コンパイラに受け入れられるとは思っていませんでした。しかし、LINQ 風味の方法で一般的な範囲演算子を追加することは確かに素晴らしいことです。たとえば、From(n).To(1).Product() や From(n).To(m).Sum()

階乗を表現するそのような形式があった場合 (そしておそらく存在する場合)、コード コントラクトではなく、コード内で確実に使用できます。

更新 2

楽しみのために、階乗を計算する LINQ の方法を見つけました。

Enumerable.Range(1, n == 0 ? 1 : n).Aggregate((a, i) => a * i);
于 2012-11-20T08:50:17.137 に答える
1

次のことを試すことができます。

Contract.Ensures(Contract.Result<int>() == AlternativeFactorial(n));

どこにAlternativeFactorialある:

[Pure]
public static int AlternativeFactorial(int n)
{
    if(n==0)
        return 1;
    if(n > 0)
    {
        //Alternative implementation.
    }
}

もちろん、コントラクトで使用するものはすべて、副作用のないもの (純粋なもの) でなければなりません。

階乗の実装に関しては、w0lf の実装よりもコンパクトな「代替」実装を考え出すことはできません。ただし、メソッドの戻り値を int からBigIntegerに変更することを考慮する必要があります。階乗は非常に急速に大きくなる可能性があります。また、階乗値に事後条件を追加すると、メソッドが結果を返すのにかかる時間がほぼ 2 倍になることにも注意してください。CodeContractsこれは、デバッグ構成のみでビルドすることで解決できます。

于 2012-11-20T11:37:16.170 に答える