2016-11-23 10 views
-2

私は今経験しているような問題を何時間も探していますが、何も見つけられず、また何も見つかりません。ここや他のウェブサイトにはありません。申し訳ありませんC++ Do - 条件が満たされても無限ループ中(理由を理解できない)

#include <iostream> 
using namespace std; 

int main() 
{ 
    double Numero=0, ParteDecimale=0, Controllo=0, Controllo2=0; 
    int ParteIntera=0; 
    string Var1="1", Var0="0", NumeroFinale; 
    cout<<"\n\n\tBenvenuto, questo programma ti consente di convertire la parte\n" 
      "\tdecimale di un numero in sistema binario. Per iniziare, inserisci un numero: "; 
    cin>>Numero; 
    cout<<Numero<<" Numero\n\n"<<endl; // 
    ParteIntera=Numero; //casting implicito, in modo da poter isolare esclusivamente la parte decimale del numero inserito. 
    cout<<ParteIntera<<" ParteIntera\n\n"<<endl; // 
    ParteDecimale=Numero-ParteIntera; //Isolamento della parte decimale 
    cout<<ParteDecimale<<" ParteDecimale\n\n"<<endl; // 
    Controllo2=ParteDecimale; 

do{ 
    ParteDecimale=ParteDecimale*2; //Moltiplicazione della parte decimale per due 
    cout<<"\n\nParteDecimaleCiclo "<<ParteDecimale<<endl; // 



    if(ParteDecimale<1){ 
     NumeroFinale=NumeroFinale+Var0; 
     cout<<"\n\nNumeroFinaleMin1 "<<NumeroFinale<<endl; // 
    } 
    else{ 
     NumeroFinale=NumeroFinale+Var1; 
     cout<<NumeroFinale<<" NumeroFinaleMagg1\n\n"<<endl; // 
     ParteDecimale-=1; 
     cout<<ParteDecimale<<" ParteDecimaleMagg1\n\n"<<endl; 
    } 
    Controllo=ParteDecimale; 
    cout<< "\n\nCONTROLLO " <<Controllo; // 
    cout<<"\n\nNUMERO "<<Numero; // 
    } 
    while(Controllo!=Controllo2); 

cout<<NumeroFinale<<endl; 
} 

..コードが厄介ですが、私は期待どおりに働いていなかったことを見たとき、私はプロセスと一緒に従うために、出力にすべての値を決定し、それは奇妙なことだ場合、コードはまったく同じように動作します結果が大丈夫であれば、条件が満たされてもdo-whileループを終了することを拒否します。例えば

-I入力「12.2」、「ParteIntera」変数内の番号(intで、私は小数部分を削除することをやっている)プログラム店。

- それ記憶「ParteDecimale」内側「ヌメロ-ParteIntera」(ヌメロ私は初めに入力された入力である)、この時点で「ParteDecimale」は0.2に等しいです。

- "ParteDecimale"の値は "Controllo2"の内部に格納されます。

- これは基本的に "ParteDecimale * 2"を実行するDo-Whileループを開始するので、 "0.4"です。

- ParteDecimaleが1より大きいか小さいかをチェックし、これに基づいてif文内でistructionsを実行します。

- ifステートメントから取得された "ParteDecimale"の値は、 "Controllo"(この場合は0.4)に格納されます。

- この場合、 "Controllo"と "Controllo2"はまだ異なるので、ループが開始されます。

特定の時点でParteDecimaleは0.6になるため、ParteDecimaleが起動するとParteDecimaleは1.2(0.6 * 2)になります。 1より大きいため、else文が実行され、ParteDecimaleは0.2(1.2-1)になります。この時点で、 "Controllo"と "Controllo2"は両方とも0.2であるため、do-while内の条件はもはや満たされず、ループは終了するはずです。

BUT

なぜ、終わらないのかわかりません。コードを実行すると、すぐにループ内のどこかをクリックしてループを一時停止する必要があります)、すべてのステップが正しいと思われます。おそらく、愚かな間違いや見えないものですが、もはや私の頭を叩く場所を知りません。

この非常に長い記事をお読みいただきありがとうございました。ご協力いただきありがとうございました。私の悪い英語を申し訳ありません。

+4

このような問題を解決する適切なツールは、デバッガです。スタックオーバーフローを尋ねる前に、コードを一行ずつ進める必要があります。詳しいヘルプは、[小さなプログラムをデバッグする方法(Eric Lippert)](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/)を参照してください。最低限、問題を再現する[最小、完全、および検証可能](http://stackoverflow.com/help/mcve)の例と、その問題を再現するためのデバッガ。 –

+6

'==' 2つの浮動小数点値を決して比較しないでください。それらのn番目の小数はおそらく異なるでしょう。そのようなことにイプシロンデルタを使うようにしてください。 – Ceros

答えて

5

実行このスニペット

float value = 2 * 0.3; 

if (value == 0.6) 
    std::cout << "Exactly" << std::endl; 
else 
    std::cout << "Ooops" << std::endl; 

そして、あなたは出力が

0.600000024 

のようなもの

if (value >= 0.6 && value <= 0.6001) 
+0

ありがとうございます、私はC++には新しく、基本的なことはまだ分かりません。正しい方向に向いてくれてありがとう! –

1
をイプシロン - デルタのロジックを使用してみてくださいではなく、正確な値であることがわかります

私はCerosが彼のコメントに正しいと思います。浮動小数点値の比較は、丸めの違いによって非常にエラーが発生しやすいです。

したがって、一般的なアプローチは、この関数のように、比較するための許容値を使用することです。

bool AreEqual(double value1, double value2) 
{ 
    double tolerance = 0.0001; 
    return fabs(value1 - value2) < tolerance; 
} 

はあなたのコードでは、このように条件を変更します

while(!AreEqual(Controllo,Controllo2)); 
+1

はい、私はCerosが正しいと確信しています.2つの浮動小数点値の比較が最善の解決策ではないことはわかりませんでした。あなたの返事もありがとう! –

1

問題はここにある:

while(Controllo!=Controllo2); 

あなたが等しくなるように期待していた変数の型doubleです。浮動小数点数は、コンピュータで正確に表現することはできません。

紙の計算では鉛筆では正確に表現されませんが、最初の小数点が等しい場合は2つの値が等しいと見なす傾向があります。コンピュータはこのように動作しません。 Controllo == Controllo2 2つの変数がまったく同じ値を持つ場合に限り、最下位桁を上にします。彼らはそれをするように指示されていない場合、コンピュータは丸めを行いません。

解決策は簡単です(これは実装した数学的アルゴリズムの一部です)。ループが2つの値が十分に近くなるまでループします。

while(fabs(Controllo - Controllo2) > 0.0001); 

あなたが知っている場合は、事前にControlloControllo2の値は、あなたが選ぶことができますどのように大きなまたは小さな:ということは、2つの値の絶対値の差が小さい値より小さいときは、事前に選ぶ停止します一定の値を比較のために使用します。上記の私の例では0.0001です。ControlloControllo2という大きな値で正常に動作します。 ControlloControllo2の値が0.001以下の場合、はるかに小さい値を使用する必要があります。

あなたは、あなたがそれらの相対的な差を確認することができます比較値であり、どのように大規模なまたはどのように小さな事前に伝えることはできません。

while(fabs((Controllo - Controllo2)/Controllo2) > 0.0001); 

Controllo2がゼロではないと仮定)。式は、ControlloControllo2のどちらがゼロでないかをチェックし、除算器として使用できる関数で抽出できます。

+0

凄い説明、ありがとうございました!私がしようとしていることに合ったものを見つけるまで、ここに掲載されているすべての例を試してみよう。ありがとうございます。 –

+0

もう一度、コードを実装したときとまったく同じように実装しようとしましたが、0.2の倍数の値に対してのみ機能します。つまり、0.1または0.3を挿入すると入力が機能しなくなるが、0.2; 0.4; 0.6; 0で機能する。8など!なぜ私に説明していただけますか?私は値で少しの周りをプレイしようとしたが、私はそれを得ることができない –

関連する問題