tags:

views:

180

answers:

7
+3  Q: 

Comparing doubles

I'm writing a program that consists of a while loop that reads two doubles and prints them. The program also prints what the larger number is and what the smaller number is.

this is the code i have so far.

int main()
{

                                    // VARIABLE DECLARATIONS 

    double a;
    double b;

    while (a,b != '|')              //WHILE A & B DO NOT EQUAL '|'
    {
        cin >>a >>b;
        cout << a << b << "\n" ;


        if (a<b)                    //IF A<B: SMALLER VALUE IS A
        cout << "The smaller value is:" << a << endl 
             << "The larger value is:" << b << endl ;

        else if (b<a)               //ELSE IF B<A 
            cout << "The smaller value is:" << b << endl 
                 << "The larger value is:" << a << endl ;
        else if (b==a)
            cout << "The two numbers you entered are equal." << "\n" ;

    }
}

The next step is having the program write out "the numbers are almost equal" if the two numbers differ by less than 1.0/10000000. How would I do this?

+6  A: 

std::abs(a - b) < 0.000001

Of course, replace the constant with whatever you consider "almost".

Billy ONeal
@Peter: Fixed. Thanks.
Billy ONeal
Also, note that the "error" will scale up with the size of a and b.
Fredrik
@Fredrik: True, but the OP specified "two numbers differ by less than SOMECONSTANT". Of course, you could cobble together something checking if the exponents on the values were the same, and then using a similar constant on the mantissas only.
Billy ONeal
@Billy ONeil: Yes, I just wanted to add it as an extra piece of information. I see way too much code written by people without basic understanding of why the "less than 1e-10" is not always working to keep quiet about it :-). I didn't expect you to alter your answer, I just thought it was overkill to write a more complete one myself. Comparisons is just one side of the problem, you will see another side when adding, multiplying etc as well. Maybe incorrectly, I assumed the OP didn't have that knowledge/experience yet.
Fredrik
This answer is also wrong for very small a and b...
Michael Goldshteyn
@Michael: Yes, that's why you got +1 from me for use of `std::numeric_limits` :P
Billy ONeal
+3  A: 

Just test if they differ by less than that amount :)

if ( std::abs(a - b) < 1.0 / 10000000 )
  cout << "The numbers are almost equal.\n";
Peter Alexander
+1 because I forgot about the abs part.
Billy ONeal
I tried this but I'm getting an error that reads "Call of overloaded 'abs(double)' is ambiguous"
Capkutay
Capkutay: Did you #include `<cmath>` ? That's required for `std::abs` to work. It's also possible you've got a `using namespace std;` somewhere, which is bad practice, and could cause a conflict between `std::abs` and `abs` in the global namespace. (`abs` is allowed, but not required, to be put in the global namespace, because it is inherited from C) Fix that by removing the `using namespace std;` and qualifying your calls to the standard library as appropriate.
Billy ONeal
+1  A: 
if (a * 1.0000001 > b  &&  a < b*1.0000001)

You can add an error value (your 1.0 / 10000000.0 ) but it is generally better to use a multiplier, so the comparison is to the same level of accuracy.

winwaed
The other answers are going for the absolute error value. This might even be quicker, but is only accurate when you know the order of magnitude of the two values.
winwaed
A: 

abs(a - b) < 1.0 / 10000000

Klark
+9  A: 

Here is how I would test for equality, without a large "fudge factor":

if (std::abs(a-b)<2.0*std::numeric_limits<double>::epsilon())
  std::cout << "The numbers are equal\n";

Or, if a and b are relatively large, you can expand this, to account for the (floor of the) maximum digits (≈15.955) that a double can represent:

if (std::abs(a-b)<2.*std::numeric_limits<double>::epsilon() || // For small a, b
    std::abs(a-b)<std::min(a,b)/1.e-15) // For large a, b
  std::cout << "The numbers are equal\n";

Finally, I recommend that you rethink your while (a,b != '|') construct, because it most likely does not do what you think.

Michael Goldshteyn
+1 for use of `std::numeric_limits`
Billy ONeal
A: 

If you want the test to scale with a and b, you could try testing abs(a/b-1) < e, where e is your favorite tiny number, like 0.001. But this condition is actually asymmetrical in a and b, so it can work out to say a is close to b, but b is not close to a. That would be bad. It's better to do abs(log(a/b)) < e, where e, again, is your favorite tiny number. But the logarithms present extra computation, not to mention terrifying undergraduates everywhere.

Josephine
1. "favorite tiny number` should probably be `std::numeric_limits<double>::epsilon()`, 2. Log is probably not the best way to handle this anyway. If you want a comparison similar to this, you should be checking the sign and exponent for equality and then compare the significands allowing for some error value. (Use `frexp` to do that -- it should perform much better than `log` or `log10`)
Billy ONeal
A: 

I suggest the following article: Comparing floating point numbers

Tomek