C ++ Do-While无限循环,即使条件满足(无法理解为什么)

时间:2016-11-23 19:59:19

标签: c++ infinite-loop do-while

我一直在寻找与我现在遇到的问题类似的问题,但是我找不到任何东西,也没有找到任何东西,也没有找到其他网站。

#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”中存储“Numero-ParteIntera”(Numero是我在开头输入的输入),此时“ParteDecimale”等于0.2;

- “ParteDecimale”的值存储在“Controllo2”;

- 这里开始Do-While循环,基本上是“ParteDecimale * 2”,所以它是“0.4”;

- 检查ParteDecimale是大于还是小于1,并在此基础上执行if语句中的istructions;

- 从if语句获得的“ParteDecimale”的值然后存储在“Controllo”中(在这种情况下它是0.4);

- 检查条件,在这种情况下“Controllo”和“Controllo2”仍然不同,所以循环重新开始;

在某一时刻,ParteDecimale将为0.6,因此当循环开始时ParteDecimale变为1.2(0.6 * 2)。由于它大于1,因此执行else语句并且ParteDecimale变为0.2(1.2-1)。此时“Controllo”和“Controllo2”都是0.2,因此do-while内的条件不再满足,循环应该结束。

BUT

我无法理解为什么,它没有结束。如果您运行代码,您将看到(您必须快速单击cmd内的某个位置以暂时停止循环)所有步骤都是正确的,可能是一个愚蠢的错误或我看不到的东西,但是现在我不知道我知道在哪里敲我的脑袋了。

感谢您阅读这篇很长的帖子,感谢任何帮助,对不起我糟糕的英语感到抱歉!

3 个答案:

答案 0 :(得分:5)

运行此代码段

float value = 2 * 0.3;

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

你会看到输出类似于

0.600000024

尝试使用epsilon-delta逻辑而不是精确值

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

答案 1 :(得分:1)

我认为Ceros的评论是对的。由于舍入差异,比较浮点值非常容易出错。

所以常见的方法是使用一些容差值来比较,就像在这个函数中一样。

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

在你的代码中你会改变这样的条件:

while(!AreEqual(Controllo,Controllo2));

答案 2 :(得分:1)

问题在于:

while(Controllo!=Controllo2);

您期望相等的变量属于double类型。浮点数不能在计算机中准确表示。

它们在纸上计算时并不完全用铅笔表示,但是当它们的第一个小数相等时,我们倾向于认为两个值相等。计算机不能以这种方式工作。 Controllo == Controllo2仅当两个变量具有完全相同的值时,才会增加其最低有效数字。如果没有告知他们这样做,计算机就不会进行任何舍入。

解决方案很简单(它也是你实现的数学算法的一部分):循环直到两个值足够接近另一个。这意味着,当两个值的绝对差值小于您提前选择的小值时停止:

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

如果您事先知道ControlloControllo2的值有多大或多小,那么您可以选择一个常量值并将其用于比较。在我上面的示例中,这是0.0001,它适用于ControlloControllo2的大值。如果ControlloControllo2的值大小为0.001或更小,则应使用更小的值。

如果您无法预先判断出比较的值有多大或多小,那么您可以检查它们的相对差异:

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

(假设Controllo2不为零)。可以在一个函数中提取公式,该函数可以检查ControlloControllo2中的哪一个不为零,并将其用作分隔符。