理論的にバグのないプログラム


12

私は、コードにバグがないことはできないと述べている多くの記事を読んでおり、彼らはこれらの定理について話している:

実際、ライスの定理は停止問題の含意のように見え、停止問題はゲーデルの不完全性定理と密接な関係にあります。

これは、すべてのプログラムが少なくとも1つの意図しない動作をすることを意味しますか?それとも、それを検証するコードを書くことができないということですか?再帰チェックはどうですか?2つのプログラムがあると仮定しましょう。どちらにもバグがありますが、同じバグを共有していません。それらを同時に実行するとどうなりますか?

そしてもちろん、ほとんどの議論はチューリング機械について話しました。線形境界の自動化(実際のコンピューター)はどうですか?


10
このpythonプログラムは、意図したことをすべて実行し、それ以上のことはしないと確信しています:print "Hello, World!"...もう少し明確にできますか?
durron597

2
@ durron597:そのようなソフトウェアの市場はありますか?Hello world printers、リロードされたバージョン?こんにちは、より多くの世界で?
JensG

1
@Phoshi笑 (たとえば、ブレッドボード上のワイヤを使用して)バグのないプロセスのスコープ全体を一度に確認できる十分に単純なプログラムを作成することは十分可能です。あなたは私の主要な点に取り組むことなく私のコメントの詳細を攻撃しています。つまり、バグのない非常に単純なプログラムを書くことができるということです。
durron597

2
@Phoshi「Pythonインタープリターにバグがないことを証明してください。」Python実装のバグは、プログラムを間違ったものにしません。Python実装が言語仕様に準拠していると想定されていることを実行する場合、プログラムは正しいです。どんな証明でも公理としていくつかのものを取ります-例えば、あなたは宇宙がプログラムの実行中ずっと存在し続けると仮定しなければなりません。CPythonにバグがある場合、結果は間違っている可能性がありますが、プログラムに問題はありませんでした。
ドーバル

11
これらの定理のどれも持っていない何もバグやバグフリープログラムの存在をどうするの。それらは、計算によって答えられる質問に関する定理です。これらの定理があることを示しているいくつかの計算できない問題、およびいくつかの実績のないまたは反証もできない数学的命題は、彼らは確かにいることを言っていないすべてのプログラムがバグを持っているか、特定のプログラムが正しい証明することができないこと。
チャールズE.グラント

回答:


18

プログラムにバグがないわけではありません。あなたが証明しようとしているプログラムが自明ではない場合、それらを証明することは非常に難しいということです。

試していないからではありません。型システムは、ある程度の保証を提供することになっています。Haskellには、これをある程度行う高度に洗練された型システムがあります。しかし、不確実性をすべて取り除くことはできません。

次の機能を検討してください。

int add(int a, int b) { return a + b; }

この機能で何が問題になるのでしょうか?私はあなたが何を考えているかすでに知っています。オーバーフローのチェックなど、すべてのベースをカバーしたとしましょう。宇宙線がプロセッサに衝突し、プロセッサが実行されるとどうなりますか

LaunchMissiles();

代わりに?

OK、それは少し不自然かもしれません。しかし、add上記の、プロセッサが常にコンテキストを変更し、複数のスレッドとコアを切り替える環境で動作する必要があります。そのような環境では、何でも起こり得ます。これを疑う場合は、RAMにエラーがないことではなく、必然的に発生するビットエラーを修正する組み込みシステムがあるため、RAMの信頼性を考慮してください

私はあなたが考えていることを知っています。「しかし、私はハードウェアではなくソフトウェアについて話している」

ソフトウェアが想定どおりに機能するという信頼レベルを向上させることができる多くのテクニックがあります。関数型プログラミングもその1つです。関数型プログラミングを使用すると、同時実行性についてより適切に判断できます。しかし、関数型プログラミングは証明ではありません。単体テスト以上のものです。

どうして?エッジケースと呼ばれるこれらのものがあるからです

また、の単純さを少しだけ超えてreturn a + bしまうと、プログラムの正確性を証明するのが非常に難しくなります。

さらなる読み物
彼らは正しいものを書く
アリアン5爆発


6
完全に型修正された関数を考えてみましょう:int add(int a, int b) { return a - b; }
ドナルドフェローズ

@DonalFellows:正確には、私はアリアン5についてのリンクが含まれていた理由である
ロバート・ハーヴェイ

2
@DonalFellows-数学的特性評価は問題を解決せず、他の場所に移動するだけです。数学モデルが実際にクライアントのニーズを表していることをどのように証明しますか?
ムービシエル

1
@JohnGaughanモジュール間の相互依存関係を想定しています。正しいことが証明され、互いに独立していることが証明されたモジュールを考えると、それらを再帰的に組み合わせて、正しい独立した広告であることが知られているより大きなモジュールにすることができます。
ドーバル

1
@JohnGaughanモジュールの統合がバグを引き起こす場合、それらが独立していることを証明できませんでした。確立された証明から新しい証明を構築することは、公理から証明を構築することほど難しくありません。数学がそのように指数関数的に難しくなった場合、数学者は台無しになります。ビルドスクリプトにバグがある可能性がありますが、それは別のプログラムです。物事を構成しようとするときにうまくいかないミステリー要素はありませんが、副作用の数によっては、共有状態がないことを証明するのは難しい場合があります。
ドーバル

12

まず、これについて議論したいコンテキストを確立しましょう。StackExchangeのプログラマーQ&A は、理論的な結果やコンピューターサイエンスの定理ではなく、ツール/言語の実世界の存在に最も関心があることを示唆しています。

私はコードにバグがないことはできないと述べている多くの記事を読みました

そのような声明が間違っているので、私は望んでいない。大部分の大規模なアプリケーション、私の知識と経験の限りでバグがないと一般に受け入れられています

より一般的に受け入れられているのは、チューリング完全なプログラミング言語で書かれたプログラムが完全にバグがないかどうかを完全に判断するツールが存在しない(つまり、存在する可能性ではなく)ということです。

ノンプルーフは、日常的な経験の観測データと組み合わされた、停止問題の直感的な拡張です。

そこ「の証明を行うことができますが存在ソフトウェア正しプログラムが対応満たしていることを確認し、」正式なプログラムの仕様は。

これは、すべてのプログラムが少なくとも1つの意図しない動作をすることを意味しますか?

いいえ。ほとんどのアプリケーションには、少なくとも1つのバグまたは意図しない動作があることがわかっています。

それとも、それを検証するコードを書くことができないということですか?

いいえ、正式な仕様と証明アシスタントを使用して仕様に準拠していることを確認できますが、経験からわかるように、仕様外の要因(ソースコードトランスレーターとハードウェアなど)がシステム全体に存在する可能性があり、間違いが頻繁に発生します仕様自体で。

詳細な詳細については、Coqはそのようなツール/言語/システムであるを参照してください。

再帰チェックはどうですか?

知りません。私はそれについて詳しくないので、それが計算可能性の問題なのか、コンパイラーの最適化の問題なのかわかりません。


1
正式な仕様と証明アシスタントについて最初に話したことに対して+1。これは重要なポイントであり、前の回答にはありません。
Arseni Mourzenko

6

私は尋ねたいのですが、すべてのコードが少なくとも1つの意図しない動作をすることを意味しますか?

いいえ。正しいプログラムを作成できます。プログラムは正しい可能性がありますが、たとえば物理的な状況(ユーザーRobert Harveyが彼の答えでここに書いたように)のために実行が失敗する可能性がありますが、これは明確な問題です:そのプログラムのコードはまだ正しいです。より正確には、障害はプログラム自体の障害エラーではなく、それを実行する基礎となるマシン(*)の障害によって引き起こされます

(*)信頼性フィールドからfaulterrorfailureの定義を、それぞれ静的欠陥、不正な内部状態、および仕様に基づく不正な外部観測動作として借用しています(<その分野の論文>を参照) 。

それとも、それをチェックするコードを書くことができないということですか?

上記のステートメントの一般的なケースを参照してください、あなたは正しいです。

特定のXプログラムが正しいかどうかをチェックするプログラムを作成できる場合があります。たとえば、つまりシーケンス内の2つの命令で1、ような「Hello World」プログラムを定義した場合print("hello world")と、exitその入力は、それがAであればこのように報告して、順番にこれらの2つの命令で構成されるプログラムであれば、あなたは小切手というプログラムを書くことができます「hello world」プログラムを修正するかどうか。

現在の定式化を使用して実行できないことは、任意のプログラムが停止するかどうかをチェックするプログラムを作成することです。これは、一般的な場合の正確性のテストが不可能であることを意味します。


4

同じプログラムの2つ以上のバリアントを実行することは、Nバリアント(またはNバージョン)プログラミングと呼ばれる既知のフォールトトレランス手法です。これは、ソフトウェアのバグの存在の承認です。

通常、これらのバリアントは、さまざまなコンパイラを使用してさまざまな開発チームによってコーディングされ、OSの異なるさまざまなCPUで実行されることもあります。結果はユーザーに出力される前に投票されます。ボーイングとエアバスはこの種のアーキテクチャが大好きです。

共通モードのバグにつながる2つの脆弱なリンクが残ります。

  • 仕様は1つだけです。
  • 投票システムは一意または複雑です。

5
NASAや他の宇宙プログラムは、Nバリアントが頻繁にプログラマーが同じように考える問題に苦しんでいるため、欠陥が最も些細なレベルを超えている場合、共通の欠陥を持つほぼ同等のプログラムを独立して書くことになると示唆していると思います。たとえば、同じ参照情報を参照し(バイナリ検索の長年のバグを参照)、同じアルゴリズムを使用する傾向があり、同じ種類の間違いをします。
mctylr

@mctylr-それは非常に良い点です。しかし、実際には、最近まで、宇宙船にソフトウェアの複数のバリアントを格納するための十分なメモリ領域がありませんでした。彼らの答えは、テスト、テスト、テスト、すすぎ、繰り返しです。
mouviciel

スペースシャトルプログラムは、3つの独立したシステム投票構成を使用しました。反対票は、システムがもはや正しくなく、オフラインになったことを意味します(または、実際に提案しました)。

4

プログラムにはいくつかの仕様があり、特定の環境で実行されます。

(他の宇宙線の例ではaddFireMissiles は、「環境」の一部と考えられるように)

プログラムの意図する動作(つまり、その仕様)とその環境を正式に指定できると仮定すると、プログラムが(その正確な意味で)バグがないことを正式に証明できる場合あります(したがって、その動作または出力は形式化における仕様の形式化を尊重します)その環境の)。

特に、Frama-Cなどの静的サウンドソースアナライザーを使用できます。

(しかし、このような解析器の技術の現状は、プログラム全体の解析&GCCコンパイラまたはFirefoxブラウザまたはLinuxカーネルのような大規模なプログラムの証明を許可していません。そして、私の信念は、そのような証拠は私の一生の間に起こらないということです。私は1959年に生まれました)

ただし、証明したのは、一部の環境(クラス)での特定の仕様に対するプログラムの正しい動作です。

実際に言えば、いくつかの宇宙船ソフトウェアが正確で形式化された仕様に対して「バグがない」ことを証明できます(そしておそらくNASAまたはESAは望みます)。しかし、それはあなたのシステムがあなたが望むようにいつも振る舞うことを意味しません。

簡単な言葉で言えば、宇宙船のロボットがETに遭遇し、それを指定していない場合、本当に望んでいるようにロボットを動作させる方法はありません....

J.Pitratのブログエントリも参照してください。

ところで、ホールティング問題またはゲーデルの定理は、おそらく人間の脳、あるいは人間の種にも当てはまります。


おそらく、SEUが呼び出しをAddに変更するより良い例は、SEUがLaunchMissiles何らかのデータ値を変更し、最終的にに誤った呼び出しを行うことLaunchMissilesです。SEUは、宇宙に入るコンピューターの問題です。これが現代の宇宙船がしばしば複数のコンピューターを飛ばす理由です。これにより、新しい問題、同時実行性、冗長性の管理が追加されます。
デビッドハンメン

3

これは、すべてのプログラムが少なくとも1つの意図しない動作をすることを意味しますか?

番号。

停止の問題は、すべてのプログラムが有限時間で停止するかどうかをテストするプログラムを作成することは不可能だということです。これは、一部のプログラムを停止、その他のプログラムを停止しないと分類できるプログラムを作成できないことを意味するものではありません。つまり、停止しているアナライザーが何らかの方法で分類できないプログラムが常に存在するということです。

ゲーデルの不完全性定理には、同様の灰色の領域があります。十分に複雑な数学的システムが与えられた場合、そのシステムのコンテキストで、真実性を評価できないいくつかのステートメントが存在します。これは、数学者が証明の考えをあきらめなければならないという意味ではありません。証明は依然として数学の基礎です。

一部のプログラムは正しいことが証明できます。簡単ではありませんが、実行できます。それが形式定理証明の目的です(形式手法の一部)。ゲーデルの不完全性定理はここにあります。すべてのプログラムが正しいことを証明できるわけではありません。一部のプログラムは実際に正しいことが正式に証明されるため、正式な方法を使用してもまったく無駄になるというわけではありません。

注:正式な方法は、宇宙線がプロセッサに衝突してのlaunch_missiles()代わりに実行される可能性を排除しa+bます。彼らは、ロバート・ハーベイの宇宙線などの単一のイベントの混乱にさらされている実際のマシンではなく、抽象的なマシンのコンテキストでプログラムを分析します。


1

そこ良い答えの多くはここにありますが、それらはすべて、このある臨界点を、周りのスカートいるように見える。これらの定理の全ては、同様の構造を持っており、同様のことを言うと、彼らが言うことはありません「それはおそらく正しい記述することは不可能ですプログラム」(ケースごとに異なる「正しい」および「プログラム」の特定の値)、しかしそれら何をする言うことは「誰かが間違っていると証明できない不正なプログラムを書くことを防ぐことは不可能です」(等)。

停止する問題の特定の例を取り上げると、違いがより明確になります。明らかに停止する可能性のあるプログラムと、停止しない可能性のある他のプログラムがあります。どちらの方法でも振る舞いを決定できないプログラムの3番目のクラスが存在することは、そのクラスに属するプログラムの作成を単純に回避できるため、証明可能な停止プログラムを作成するだけであれば問題になりません。

同じことがライスの定理にも当てはまります。はい、プログラムの重要な特性については、その特性を真でも偽でも証明できないプログラムを書くことができます。また、プログラムが証明可能かどうかを判断できるため、このようなプログラムの作成を回避できます。


0

私の答えは、実世界のビジネスとすべての開発チームが直面する課題の観点からです。この質問と多くの答えで私が見ているのは、実際に欠陥を制御することです。

コードにはバグがない可能性があります。任意のプログラミング言語の「Hello World」コードサンプルのいずれかを取得し、それを意図したプラットフォームで実行すると、一貫して動作し、目的の結果が生成されます。バグのないコードの不可能性に関する理論は終わりです。

ロジックがより複雑になると、潜在的なバグが入ります。単純なHello Worldの例にはロジックがなく、毎回同じ静的なことを行います。ロジック駆動の動的な動作を追加するとすぐに、バグにつながる複雑さが生じます。ロジック自体に欠陥があるか、ロジックに入力されるデータがロジックが処理しない方法で変化する可能性があります。

最新のアプリケーションは、ランタイムライブラリ、CLR、ミドルウェア、データベースなどのレイヤーにも依存しています。これらのレイヤーは、全体的な開発時間を節約する一方で、それらのレイヤー内のバグが存在し、開発およびUATテストを通じて本番環境に検出されないレイヤーにもなります。

最後に、アプリケーションがロジックを供給するデータを消費するアプリ/システムのチェーンはすべて、ロジック内、またはロジックがその上に乗るソフトウェアスタック内、またはデータを消費するアップストリームシステム内の潜在的なバグの原因です。

開発者は、アプリケーションのロジックをサポートするすべての可動部分を完全に制御できるわけではありません。実際、私たちは多くを管理していません。ユニットテストが重要であり、構成と変更管理は重要なプロセスであり、無視したり怠けたりしてはいけません。

また、制御不能なソースからデータを消費するアプリケーション間の文書化された合意、転送されたデータの特定の形式と仕様、およびソースシステムが出力が確実に内にあると想定する制限または制約を定義しますそれらの境界。

ソフトウェアエンジニアリングの実世界のアプリケーションでは、理論的にアプリケーションにバグがない理由をビジネスに説明することで、飛ばすことはできません。テクノロジーとビジネスの間のこの性質についての議論は、ビジネスの金makeけ、お金の損失の防止、および/または人々の生存能力に影響を与えた技術的な誤作動の後を除き、決して起こりません。「どうしてこうなるのか」に対する答えは、「この理論を説明して、あなたが理解できるようにする」ことはできません。

理論的には計算を実行して結果を得るのに永遠にかかる可能性のある大規模な計算に関しては、結果で終了して戻ることができないアプリケーション、つまりバグです。計算の性質が非常に時間がかかり、計算が集中するようなものである場合、そのリクエストを受け取って、結果を取得する方法とタイミングをユーザーにフィードバックし、並列スレッドを開始して解約します。これを1つのサーバーで実行できるよりも迅速に行う必要があり、ビジネス上十分に重要な場合は、必要な数のシステムでスケールアウトします。これがクラウドが非常に魅力的である理由であり、ノードをスピンアップして仕事を引き受け、完了時にそれらをスピンダウンする機能です。

計算能力の量を完了できないという要求を取得する可能性が存在する場合、ビジネスプロセスが有限の問題であると考えるものへの答えを待っているビジネスプロセスで無限に実行する必要があります。


-2

コードが完全に終了することは決してないので、コードが100%バグフリーになるとは思わない。書いたものをいつでも改善できます。

プログラミングは科学と数学の分野であり、どちらの場合も無限です。開発者であることの素晴らしいところは、私たちの仕事が無限であることです。

1行のコードを記述する方法は、数千以上あります。アイデアは、そのコード行の最も最適化されたバージョンを記述することですが、バグがないわけではありません。バグフリーとは、コードが解読不能であり、すべてのコードがある程度または方法で破壊される可能性があるという考えを指します。

それで、コードは効率的ですか?はい。
コードを際限なく最適化できますか?はい。
コードにバグはありませんか?いいえ、あなたは単にそれを破る方法を見つけていないだけです。
そうは言っても、自分自身とコードの作成方法を改善しようと努力すると、コードが壊れにくくなります。


この投稿は読みにくい(テキストの壁)。それをより良い形に編集してもいいですか?
-gnat
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.