• 0

[C++] Why does this keep looping?


Question

#include <iostream>
#include <cmath> //used for exp
using namespace std;

//declaration of functions
double f(double x, double answer);
bool get_and_check_guesses(double& xleft, double& xright, double& answer, bool input_fail);
void do_bisection(double& xleft, double& xright, double xmid, double epsilon, double& answer, bool input_fail);




int main()

{
  double xleft, xright, xmid, epsilon, answer;
  bool input_fail;

  cout << "This program will use a bisection algorithm" << endl << endl;

  get_and_check_guesses(xleft, xright, answer, input_fail); // calling of functions
  do_bisection(xleft, xright, xmid, epsilon, answer, input_fail);

return 0;

}




double f(double x, double answer)

{
	answer = (exp(-0.2 * x) * cos(x - 0.7)) + (exp(-0.15 * x) * cos(1.5 * (x - 0.4))); // main calculation
	return answer;
}




bool get_and_check_guesses(double& xleft, double& xright, double& answer, bool input_fail)

{

	cout << "Please enter xleft: ";
	cin >> xleft;

 	 input_fail = cin.fail();
 	 if (input_fail == true)
 	 {
    cout << "Incorrect input. This program will now close." << endl;
    return 0;
 	 }

	cout << "Please enter xright: ";
	cin >> xright;

 	 input_fail = cin.fail();
 	 if (input_fail == true)
 	 {
    cout << "Incorrect input. This program will now close." << endl;
    return 0;
 	 }

  if ((xleft < xright) && (f(xleft, answer) < 0) && (f(xright, answer) > 0)) //checks if xleft < xright and if f(xleft) is less than f(xright)
 	 {
    return true;
 	 }
  else
 	 {
    cout << "xleft has to be smaller than xright, and f(xleft) must be of the opposite sign of f(xright)" << endl;
    return false;
 	 }
}



void do_bisection(double& xleft, double& xright, double xmid, double epsilon, double& answer, bool input_fail)

{

	cout << "Please enter a value for epsilon: ";
	cin >> epsilon;

 	 input_fail = cin.fail();
 	 if (input_fail == true)
 	 {
    cout << "Incorrect input. This program will probably output an error." << endl;
 	 }

	while ((xright - xleft) > epsilon)
  {
    xmid = (0.5 * (xleft + xright));

 	 if (get_and_check_guesses(xleft, xright, answer, input_fail)) // checks is previous function returned true or false
    {
   	 xright = xmid;
    }
 	 else
    {
   	 xleft = xmid;
    }
  }
	cout << "xleft and xright are: " << xleft << " " << xright << endl;
}

Basically I'm having a few problems with this program I'm trying to write.

This is my output:

Please enter xleft: -5

Please enter xright: 6

xleft has to be smaller and of the opposite sign of xright

Please enter a value for epsilon: 2

Please enter xleft: -5

Please enter xright: 7

xleft has to be smaller and of the opposite sign of xright

Please enter xleft: no

Incorrect input. This program will now close.

Please enter xleft: Incorrect input. This program will now close.

xleft and xright are: 5.375 7

I know it's a mess, but why am I looping back to 'please enter xleft', and why is my program telling me that -5 is not smaller than 6?

Link to comment
Share on other sites

15 answers to this question

Recommended Posts

  • 0

Haven't finished looking through yet, but here's something I see that's somewhat odd:

double f(double x, double answer)

{

answer = (exp(-0.2 * x) * cos(x - 0.7)) + (exp(-0.15 * x) * cos(1.5 * (x - 0.4))); // main calculation

return answer;

}

Why do you use the second argument to do the calculations instead of doing a:

double f(double x)

{

return (exp(-0.2 * x) * cos(x - 0.7)) + (exp(-0.15 * x) * cos(1.5 * (x - 0.4))); // main calculation

}

The way you have it is pointless. And I'm guessing this is probably the part that's causing it to say xleft is not smaller than xright, although I'm not sure why. Actually I know why, you're seeing if the result is less than 0, which it won't be I think. Perhaps you mean > 0? What you're doing doesn't match up with your comment "//checks if xleft < xright and if f(xleft) is less than f(xright)" either. Do you mean f(xleft) < f(xright) ?

And on the looping:

while ((xright - xleft) > epsilon)

That's the source of your trouble. xright - xleft is greater than the epsilon you're inputting, much bigger, 11 and 12 vs 2, so you're looping.

Edited by kjordan2001
Link to comment
Share on other sites

  • 0

(f(xleft) < 0) && (f(xright) > 0))

In that portion, I'm trying to make sure that the result of the main calculation with xleft is NEGATIVE and less than the result of the main calculation with xright.

Having f(xleft) < f(xright) by itself won't suffice.

As for the bottom part:

while ((xright - xleft) &lt; epsilon)
  {
    xmid = (0.5 * (xleft + xright));

 	 if (get_and_check_guesses(xleft, xright, input_fail)) // checks is previous function returned true or false
    {
   	 xright = xmid;
    }
 	 else
    {
   	 xleft = xmid;
    }
  }
	cout &lt;&lt; "xleft and xright are: " &lt;&lt; xleft &lt;&lt; " " &lt;&lt; xright &lt;&lt; endl;

I want to keep looping this (notice the 0.5 * part) until xright − xleft < epsilon

Basically xmid keeps being substituted in, and each xright and xleft keeps being divided by a half until xright - xleft < epsilon

As long as xright - xleft > epsilon, I want the function to continue looping until that condition is no longer valid.

Link to comment
Share on other sites

  • 0
(f(xleft) < 0) && (f(xright) > 0))

In that portion, I'm trying to make sure that the result of the main calculation with xleft is NEGATIVE and less than the result of the main calculation with xright.

Having f(xleft) < f(xright) by itself won't suffice.

As for the bottom part:

while ((xright - xleft) &lt; epsilon)
  {
    xmid = (0.5 * (xleft + xright));

 	 if (get_and_check_guesses(xleft, xright, input_fail)) // checks is previous function returned true or false
    {
   	 xright = xmid;
    }
 	 else
    {
   	 xleft = xmid;
    }
  }
	cout &lt;&lt; "xleft and xright are: " &lt;&lt; xleft &lt;&lt; " " &lt;&lt; xright &lt;&lt; endl;

I want to keep looping this (notice the 0.5 * part) until xright − xleft < epsilon

Basically xmid keeps being substituted in, and each xright and xleft keeps being divided by a half until xright - xleft < epsilon

As long as xright - xleft > epsilon, I want the function to continue looping until that condition is no longer valid.

584806524[/snapback]

So what's the problem then? You said you wondered why it was looping, and that's your answer, it's not < epsilon. Actually it's this line:

if (get_and_check_guesses(xleft, xright, input_fail)) // checks is previous function returned true or false

that's doing it. That function gets input again.

And do a hand calculation on what's going into that f function, I'll bet one of those is the problem. And yep, it is, you're not getting a negative value for your -5. I get a positive 4.8 in fact.

Edited by kjordan2001
Link to comment
Share on other sites

  • 0
It's going back and asking for xleft and xright again. The program should be updating them automatically.

584806615[/snapback]

It's not though, you've got it calling a function that asks for input again. You either need to split that input and check function into 2 functions, or have some check in that function.

Link to comment
Share on other sites

  • 0

Where am I calling it again?

Is it this:

if (get_and_check_guesses(xleft, xright, input_fail)) ?

Because I'm basically trying to make an IF statement that says if that function returns a value of TRUE, then xright = xmid.

Link to comment
Share on other sites

  • 0
Where am I calling it again?

Is it this:

if (get_and_check_guesses(xleft, xright, input_fail))  ?

Because I'm basically trying to make an IF statement that says if that function returns a value of TRUE, then xright = xmid.

584806901[/snapback]

Yes, look at what that function does, it asks for input into xleft and xright. You probably want to break get_and_check_guesses into two functions. One for input and one for checking.

Link to comment
Share on other sites

  • 0

I also have this code in there now:

cin &gt;&gt; epsilon;

 	 input_fail = cin.fail();
 	 while (input_fail == true)
 	 {
    cout &lt;&lt; "Incorrect input for epsilon. Try again: ";
    cin &gt;&gt; epsilon;
 	 }

But it sends me in an infinite loop. Am I missing a check for cin.fail again or something?

Link to comment
Share on other sites

  • 0
I also have this code in there now:

cin &gt;&gt; epsilon;

 	 input_fail = cin.fail();
 	 while (input_fail == true)
 	 {
    cout &lt;&lt; "Incorrect input for epsilon. Try again: ";
    cin &gt;&gt; epsilon;
 	 }

But it sends me in an infinite loop. Am I missing a check for cin.fail again or something?

584807047[/snapback]

Yep, you only check it once, so input_fail is always true (assuming it's true and gets into the loop).

Link to comment
Share on other sites

  • 0
How would I go about checking it again?

I tried adding "input_fail = cin.fail();" after the second cin >> epsilon, but I'm getting the same result.

584807074[/snapback]

cin >> epsilon;

while (cin.fail())

{

cout << "Incorrect input for epsilon. Try again: ";

cin.clear();

fflush(stdin);

cin >> epsilon;

}

Try that, cin.clear() clears the fail bit and fflush(stdin) clears the input stream.

Link to comment
Share on other sites

  • 0

It *kinda* works now... but look:

Please enter xleft: 3
Please enter xright: 5
Please enter a value for epsilon: no
Incorrect input for epsilon. Try again: 3
Incorrect input for epsilon. Try again: 4
Incorrect input for epsilon. Try again: 5

Link to comment
Share on other sites

  • 0

 int epsilon = 0;
  for (cin &gt;&gt; epsilon; cin.fail(); cin &gt;&gt; epsilon)
  {
    cin.clear();
    cin.ignore(INT_MAX, '\n');
    if (cin.eof())
      exit(1);
    cout &lt;&lt; "Incorrect input for epsilon. Try again: " &lt;&lt; flush;
  }

Try that one...

Link to comment
Share on other sites

  • 0
That worked.

Could you explain what's going on in there? I didn't learn that in class yet, but it's definitely something I'd like to use in the future.

584807197[/snapback]

Well, like I said, cin.clear() clears the fail flag. cin.ignore(INT_MAX, '\n'); clears to the end of the line. cin.eof() sees if it ran into an EOF (END OF FILE), i.e. if you were reading from a text file, or the user hit ctrl+d in Linux, can't remember at the moment what EOF is in Windows.

Link to comment
Share on other sites

This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.