-2

I have been searching for hours an issue similar to the one I'm experiencing right now, but I can't find anything, nor here nor in other websites.

#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; 
}

Sorry if the code is messy, but when I saw that it was not working as expected I decided to output every value to follow along with the process, and that's the weird thing.. The code acts exactly as expected and the results are all right, it just refuses to exit the do-while loop even if the condition is satisfied.

For example:

-I input "12.2", the program store the number inside the "ParteIntera" variable (which is an int, I'm doing that to remove the decimal part);

-It stores "Numero-ParteIntera" inside "ParteDecimale" (Numero is the input I entered at the beginning), and at this point "ParteDecimale" is equal to 0.2;

-The value of "ParteDecimale" is stored inside "Controllo2";

-Here starts the Do-While loop, that basically does "ParteDecimale*2", so it's "0.4";

-It checks if ParteDecimale is bigger or smaller than 1, and based on this it executes the istructions inside the if statements;

-The value of "ParteDecimale" that is obtained from the if statement is then stored inside "Controllo" (In this case it's 0.4);

-The condition is checked, in this case "Controllo" and "Controllo2" are still different so the loop starts over;

At a certain point ParteDecimale will be 0.6, so when the loop starts ParteDecimale become 1.2 (0.6*2). Since it's bigger than 1, the else statement is executed and ParteDecimale become 0.2 (1.2-1). At this point "Controllo" and "Controllo2" are both 0.2, so the condition inside the do-while is not satisfied anymore and the loop should end.

BUT

I can't understand why, it is not ending. If you run the code you will see (you have to quickly click somewhere inside the cmd to temporarily stop the loop) that all the steps are right, probably it's a stupid mistake or something I can't see, but right now I don't know where to bang my head anymore.

Thanks for reading this very long post, any help is appreciated, and sorry for my bad english!

  • 4
    The right tool to solve such problems is your debugger. You should step through your code line-by-line *before* asking on Stack Overflow. For more help, please read [How to debug small programs (by Eric Lippert)](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/). At a minimum, you should \[edit] your question to include a [Minimal, Complete, and Verifiable](http://stackoverflow.com/help/mcve) example that reproduces your problem, along with the observations you made in the debugger. – πάντα ῥεῖ Nov 23 '16 at 20:00
  • 6
    Never compare `==` two floating-point values. Their n-th decimal will probably be different. Try to use an epsilon delta for such thing. – Ceros Nov 23 '16 at 20:03

3 Answers3

5

Run this snippet

float value = 2 * 0.3;

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

And you will see that the output is something like

0.600000024

Try to use an epsilon-delta logic rather than an exact value

if (value >= 0.6 && value <= 0.6001)
Ceros
  • 491
  • 3
  • 14
  • Thank you, as you can see I'm pretty new to C++, and still I don't understand all the basics. Thanks a lot for pointing me in the right direction! – Dennis Preatto Nov 23 '16 at 20:11
1

I think that Ceros is right in his comment. Comparing floating-point values is very error prone due to rounding differences.

So the common approach is to use some tolerance value to compare to, like in this function.

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

In your code you would change the condition like this:

while(!AreEqual(Controllo,Controllo2));
Andre Kraemer
  • 2,633
  • 1
  • 17
  • 28
  • 1
    Yes I am quite sure that Ceros is right, I didn't know that comparisons between two floating-point values aren't the best solution. Thank you for your reply too! – Dennis Preatto Nov 23 '16 at 20:14
1

The problem is here:

while(Controllo!=Controllo2);

The variables you expect to be equal are of type double. The floating point numbers cannot be represented exactly in computers.

They are not represented exactly in pencil on paper calculations either but we tend to consider two values equal when their first decimals are equal. The computers do not work this way. Controllo == Controllo2 only when the two variables have the exact same value, up the their least significant digit. The computers don't do any rounding if they are not told to do it.

The solution is simple (and it is also part of the mathematical algorithm you implemented): loop until the two values are close enough one to the other. That means, stop when the absolute difference of the two values is smaller than a small value you pick in advance:

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

If you know in advance how big or small are the values of Controllo and Controllo2 then you can pick a constant value and use it for comparison. This is 0.0001 in my example above and it works fine with large values of Controllo and Controllo2. You should use much smaller values if the values of Controllo and Controllo2 are of the magnitude of 0.001 or smaller.

When you cannot tell in advance how large or how small are the values you compare then you can check for their relative difference:

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

(assuming Controllo2 is not zero). The formula can be extracted in a function that can check which one of Controllo and Controllo2 is not zero and use it as divider.

axiac
  • 68,258
  • 9
  • 99
  • 134
  • Awesome explanation, thank you a lot! Im going to try all the examples posted here untill I find the one that suits for what I am trying to do. Thanks a lot for you time! – Dennis Preatto Nov 23 '16 at 20:16
  • Excuse me again, I just tried to implement your code, exactly as you wrote it, but it works only for value that are multiple of 0.2. I mean, if I insert 0.1 or 0.3 as input is not working but it works with 0.2;0.4;0.6;0.8 and so on! Could you please explain me why? I tried to play around a bit with values but I just can't get it – Dennis Preatto Nov 23 '16 at 20:42