C++做 - 虽然条件满足时无限循环(不明白为什么)

问题描述:

我一直在寻找类似于我现在遇到的问题的小时数,但我找不到任何东西,也找不到任何东西这里或其他网站。C++做 - 虽然条件满足时无限循环(不明白为什么)

#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内部的条件不再满足,循环应该结束。

但是

我不明白为什么,它没有结束。如果你运行代码,你会看到(你必须快速点击cmd内的某个地方暂时停止循环),所有步骤都是正确的,可能是一个愚蠢的错误或者我看不见的东西,但是现在我不'不知道该把我的头撞到哪里去了。

感谢您阅读这篇很长的文章,任何帮助表示赞赏,对不起我的英文不好!

+4

解决此类问题的正确工具是您的调试器。在*堆栈溢出问题之前,您应该逐行执行您的代码。如需更多帮助,请阅读[如何调试小程序(由Eric Lippert撰写)](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/)。至少,您应该\编辑您的问题,以包含一个[最小,完整和可验证](http://*.com/help/mcve)示例,该示例再现了您的问题,以及您在调试器。 –

+6

永远不要比较'=='两个浮点值。他们的第n小数可能会不同。尝试使用epsilon三角洲这样的事情。 – Ceros

运行这段代码

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++相当陌生,但我仍然不了解所有的基础知识。非常感谢您指点我正确的方向! –

我认为Ceros在他的评论中是正确的。由于四舍五入的差异,比较浮点值非常容易出错。

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

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

在你的代码会改变的情况是这样的:

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

是的我很肯定Ceros是对的,我不知道两个浮点值之间的比较不是最好的解决方案。谢谢你的回复! –

的问题是在这里:

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中的哪一个不为零,并将其用作分频器。

+0

真棒解释,非常感谢你!我会尝试在这里发布的所有例子,直到我找到适合我正在尝试做的事情。非常感谢您的时间! –

+0

再次抱歉,我只是试图按照您的代码实现您的代码,但它仅适用于0.2的倍数。我的意思是,如果我插入0.1或0.3作为输入不起作用,但它与0.2; 0.4; 0.6; 0一起使用。8等等!你能解释我为什么吗?我尝试了一些有价值的东西,但我无法得到它 –