-1

I know there are loads of topics about this question, but none of those helped me. I am trying to find the root of a function by testing every number in a range of -10 to 10 with two decimal places. I know it maybe isn't the best way, but I am a beginner and just want to try this out. Somehow the loop does not work, as I am always getting -10 as an output. Anyway, that is my code:

 #include <iostream>
using namespace std;

double calc (double m,double n)
{
  double x;
  for (x=-10;x<10 && m*x+n==0; x+=0.01)
  {
   cout << x << endl;
  }
  return x;
}



int main()
{
  double m, n, x;

  cout << "......\n";
  cin >> m;                         // gradient
  cout << "........\n";
  cin >> n;                         // y-intercept
  x=calc(m,n);                      // using function to calculate
  cout << ".......... " << x<< endl; //output solution
  cout << "..............\n";        // Nothing of importance
  return 0;
}
Rakib
  • 7,435
  • 7
  • 29
  • 45
MalteK
  • 167
  • 8
  • 3
    Try to avoid working with double/floats and use integers whenever you can. So something like `for (x=-1000;x<1000 && m*(x/100)+n==0; x+=1)`. Then you can divide the value of x by 100 when printing the result. – Martin Konecny May 28 '14 at 18:10
  • I updated my answer with one possibility for how you might fix it. – merlin2011 May 28 '14 at 18:19
  • You are entirely sure about what `m*x+n==0` actually does, are you? – πάντα ῥεῖ May 28 '14 at 18:29
  • But I think integers onl support full numbers, but I want it to be more precise. Oh and I have changed m*x+n==0 to m*x+n!=0 now it outputs 10 so nothing has improved – MalteK May 28 '14 at 18:45
  • @ubuntu.stuff You'll need to check against [`std::numeric_limit::epsilon`](http://en.cppreference.com/w/cpp/types/numeric_limits/epsilon) difference to `0.0` to get this right! See here [**Compare double to zero using epsilon**](http://stackoverflow.com/questions/13698927/compare-double-to-zero-using-epsilon) – πάντα ῥεῖ May 28 '14 at 19:23
  • I have edited the answer again. – merlin2011 May 28 '14 at 21:04

2 Answers2

5

You are testing the conjunction of two conditions in your loop condition.

for (x=-10;x<10 && m*x+n==0; x+=0.01

For many inputs, the second condition will not be true, so the loop will terminate before the first iteration, causing a return value of -10.

What you want is probably closer to something closer to the following. We need to test whether the absolute value is smaller than some EPSILON for two reasons. One, double is not precise. Two, you are doing an approximate solution anyways, so you would not expect an exact answer unless you happened to get lucky.

#define EPSILON 1E-2
double calc (double m,double n)
{
    double x;
    for (x=-10;x<10; x+=0.001)
    {
        if (abs(m*x+n) < EPSILON) return x;
    }

    // return a value outside the range to indicate that we failed to find a
    // solution within range.
    return -20;
}

Update: At the request of the OP, I will be more specific about what problem EPSILON solves.

  1. double is not precise. In a computer, floating point number are usually represented by a fixed number of bits, with the bit representation usually being specified by a standard such as IEE 754. Because the number of bits is fixed and finite, you cannot represent arbitrary precision numbers. Let us consider an example in base 10 for ease of understanding, although you should understand that computers experience a similar problem in base 2. If m = 1/3, x = 3, and n = -1, we would expect that m*x + n == 0. However, because 1/3 is the repeated decimal 0.33333... and we can only represent a fixed number of them, the result of 3*0.33333 is actually 0.999999, which is not equal to 1. Therefore, m*x + n != 0, and our check will fail. Thus, instead of checking for equality with zero, we must check whether the result is sufficiently close to zero, by comparing its absolute value with a small number we call EPSILON. As one of the comments pointed out the correct value of EPSILON for this particular purpose is std::numeric_limits::epsilon, but the second issue requires a larger EPSILON.

  2. You are are only doing an approximate solution anyways. Since you are checking the values of x at finitely small increments, there is a strong possibility that you will simply step over the root without ever landing on it exactly. Consider the equation 10000x + 1 = 0. The correct solution is -0.0001, but if you are taking steps of 0.001, you will never actually try the value x = -0.0001, so you could not possibly find the correct solution. For linear functions, we would expect that values of x close to -0.0001, such as x = 0, will get us reasonably close to the correct solution, so we use EPSILON as a fudge factor to work around the lack of precision in our method.

merlin2011
  • 71,677
  • 44
  • 195
  • 329
  • what is EPSILON? And could you please explain your code a bit more, I just don't understand it.:) – MalteK May 28 '14 at 18:52
  • epsilon here is a tolerance ... when dealing with floating point numbers you should be very suspicious of the '==' operator. Unless the fractional part of the double is zero or some power of two (for example .5 or .25, or .125, and so on...) it will be the closest rounded **approximation** to the real base_10 number possible in base_2. Consequently the most reliable check for "equal to zero" is to check that something is smaller than what we can practically regard as zero. – HexedAgain May 28 '14 at 18:57
  • okaay, I guess I will just wait on that program. I don't really understand much, but thanks a lot anyway:D btw. Alot of wizards around here, aren't there? Merlin2011, Hexedagain...no wonder I can´t do it... – MalteK May 28 '14 at 19:04
  • Would be worth mentioning [`std::numeric_limit::epsilon`](http://en.cppreference.com/w/cpp/types/numeric_limits/epsilon) providied with the current c++ standard. – πάντα ῥεῖ May 28 '14 at 19:26
  • 1
    @πάνταῥεῖ I am struggling to see the utility of machine epsilon for this problem. For example if m > 1, n > 0 then since log_10(m*x) > 1 then the distance between m*x + n and the next representable double will be significantly larger than machine epsilon. Conversely, if m is very small then relative to the distance between m*x and the next representable, machine epsilon could be huge! – HexedAgain May 28 '14 at 19:51
  • last comment incorrect - I meant to say if m > 1000 – HexedAgain May 28 '14 at 20:04
  • @πάνταῥεῖ To explain "machine epsilon [denote by E] could be huge". The distance between 1 and 1 + E is 2^-53. Now suppose |m*x + n| is smaller than 2^-10 , then there are over 1000 doubles between mx + n and mx + n + E! – HexedAgain May 28 '14 at 20:12
  • @HexedAgain Yeah, it's architecture dependent, and what want to you tell us besides this? – πάντα ῥεῖ May 28 '14 at 20:14
  • Essentially the sentiment was that I can't see the utility in your suggestion, as is, for this problem. – HexedAgain May 28 '14 at 20:22
  • 1
    @merlin2011, std::numeric_limits::epsilon is not correct without scaling it correctly, and that depends on the size of m – HexedAgain May 28 '14 at 21:28
  • @HexedAgain, Please suggest alternate wording to make the answer more precise (exactly how we scale it correctly for this context), and I will put in your changes. – merlin2011 May 28 '14 at 22:30
  • duuude this is complicated. Thx so much for trying tom explain it to me, I will try to follow along. But what I don't understand is why the program cannot even calculate numbers, I checked myself before. I chose a combination that would have a 1 as a root, but it just always skips the loop. Why? – MalteK Jun 01 '14 at 17:46
-1

m*x+n==0 condition returns false, thus the loop doesn't start. You should change it to m*x+n!=0

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
j3ny4
  • 442
  • 2
  • 8