web-dev-qa-db-ja.com

不変条件の破損につながる一般的な間違い

私の主な収入源はウェブ開発です。これにより、仕事や個人的な遊びを通じてさまざまな言語の知識が年々増えてきたため、プログラミングの素晴らしさを楽しむことができました。ある時点で、大学での教育が十分ではなく、コンピュータサイエンスまたはソフトウェアエンジニアリングのいずれかの大学の学位を取得するために学校に戻りたいという決断に達しました。私は人生でいろいろなことを試しましたが、情熱だと感じるものを見つけるまでに少し時間がかかりました。これがそれです。

しかし、私が見つけたこの研究分野の1つの側面は、私を失望させます。プログラムの正当性を証明する正式な方法は難しいと思います。コードを正しく書くのに問題があるわけではありません。アルゴリズムを見て、それがどのように正しいか欠陥があるかを確認できますが、これを正式な定義に変換するのに苦労することがあります。私は大学レベルで行ったすべてのプログラミング課題で完璧またはほぼ完璧な点数を獲得しましたが、最近、ウォータールー大学の男から教科書を入手し、いくつかの形式主義に関して問題があったことがわかりました。 。

さて、この時点で具体的には1つだけです。特にループで、不変条件の破損につながる一般的な間違いの良い例を提供していただければ、本当に助かります。私はソフトウェア工学とコンピュータサイエンスの教科書をいくつか持っていますが、それらは物事がどうあるべきかを示しているだけです。いつ起こったのかを認識しやすくするために、どのように問題が発生したのかを知りたいです。形式主義は実体の問題が構築される基本的な基盤であるため、この主題をブローチすることはほとんど恥ずかしいことです。

後で邪魔にならないように、今はこれを乗り越えたいと思います。

2
Dave B.

一般的な数値の問題

オーバーフロー、アンダーフロー。

何が問題になっていますか

int newArrayLength = arr.length * 2;
T[] newArray = new T[newArrayLength];

浮動小数点

<、>、<=、=>を使用して比較するときにNaNを考慮しない。

これの何が問題になっていますか

double max(double a, double b) { return a < b ? b : a; }

フィルタリング

重複の説明に失敗しました。

何が問題になっていますか

int numberOfInstancesIn(T[] items, T[] set) {
  int count = 0;
  for (int i = 0; i < items.length; ++i) {
    T item = items[i];
    for (int j = 0; j < set.length; ++j) {
      if (item == set[j]) { ++count; }
    }
  }
  return count;
}

2つのオブジェクトは名前が異なるため、同じではないと仮定します

何が問題になっていますか

class Pair {
  T* a;
  T* b;

  ~C() {
    delete a;
    delete b;
  }
}

3
Mike Samuel

私のお気に入り:正しく初期化できない

 minIndex = 0
 minValue= someRandomValue # NOT someList[minIndex]
 for i in range( 0, len(someList) ) # NOT range( 1, len(someList) ): 
     assert min(someList) == someList[minIndex] # not true initially
     if someList[i] <= someList[minIndex]:
         minIndex= i
         minValue= someList[minIndex]

初期化は実際のデータに基づいている必要があります。

他の一般的なもの-ifステートメントの存在下で不変条件を維持できない。

oddSum= 0
evenSum= 0 
for i in range( 0, len(someList) ):
    if i % 2 == 0:
        evenSum += someList[i]
    else:
        # some random statement that doesn't update oddSum
    assert evenSum + oddSum == sum( someList[0:i] )
        # The above may not always be true

秘訣はこれです。

「しかし、それらは物事がどうあるべきかを示しているだけです」ごとに、あなたはどんな声明も台無しにすることができ、あなたはエラーを起こすでしょう。

あなたは-個人的に-間違いを見ることができますが、他のランダムなプログラマーはエラーを見ていないことを認識し、不変条件を満たさないランダムなコードを書く必要があります。

これは「遺伝的プログラミング」の演習です。ランダムな突然変異を導入し、不変条件が真であるかどうかを確認します。他の人のコードを読むと、彼らが完全にランダムなエラーを犯していることがわかります。

3
S.Lott

一般に、状態の変更は、破損した不変条件の最大の原因です(実際には、のみ原因である可能性があります)。私は昔からの命令型対関数型の議論を始めるつもりはありませんが、Haskellのような言語が学者の間で非常に人気がある理由があります:純粋に関数型コードが正しいことを証明する方がはるかに簡単です。もちろん、関数型コードが一般的に優れているかどうかは、まったく別の議論です。

例として、ループの各反復後に変数fooが5未満でなければならないという不変条件がある場合、その不変条件が失敗する唯一の方法はfooの値を変更することです。したがって、コードが開始する前にfooが5未満であり、fooの値を変更しない場合、ループが終了したときにfooが5未満になることを確認できます。

1
Jason Baker