13
votes

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?

8
Smells homework, so please add the tag homework if that's the case. - Johann Gerell
Funny how far that smell can travel... - Michael Goldshteyn
@user484955: Do you really know what while (a,b != '|') means ? - Kiril Kirov
You need to do while (a != '|' && b != '|'). What you have uses the comma operator, which evaluates a, then evaluates b != '|', resulting in b != '|'. In other words, you have while (b != '|'), discarding a. Now, why you're comparing it to that, I still don't know. - GManNickG
@Capkutay: But if the user enters '|', the operator>>(std::istream&, double&) will fail, because | is not a valid double. You have to read a string, and convert to a double, instead. - Billy ONeal

8 Answers

26
votes

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

if (
    // Test 1: Very cheap, but can result in false negatives
    a==b || 
    // Test 2: More expensive, but comprehensive
    std::abs(a-b)<std::abs(std::min(a,b))*std::numeric_limits<double>::epsilon())
  std::cout << "The numbers are equal\n";

Explanation

The first test is a simple comparison. Of course we all know that comparing double precision values can result in them being deemed unequal, even when they are logically equivalent.

A double precision floating point value can hold the most significant fifteen digits of a number (actually ≈15.955 digits). Therefore, we want to call two values equal if (approximately) their first fifteen digits match. To phrase this another way, we want to call them equal if they are within one scaled epsilon of each other. This is exactly what the second test computes.

You can choose to add more leeway than a single scaled epsilon, due to more significant floating point errors creeping in as a result of iterative computation. To do this, add an error factor to the right hand side of the second test's comparison:

double error_factor=2.0;

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

I cannot give you a fixed value for the error_factor, since it will depend on the amount of error that creeps into your computations. However, with some testing you should be able to find a reasonable value that suits your application. Do keep in mind that adding an (arbitrary) error factor based on speculation alone will put you right back into fudge factor territory.

Summary

You can wrap the following test into a(n inline) function:

inline bool logically_equal(double a, double b, double error_factor=1.0)
{
  return a==b || 
    std::abs(a-b)<std::abs(std::min(a,b))*std::numeric_limits<double>::epsilon()*
                  error_factor;
}
11
votes

std::abs(a - b) < 0.000001

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

4
votes

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";
2
votes
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.

2
votes

I suggest the following article: new link
(obsolete link->Comparing floating point numbers)

1
votes

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.

1
votes
abs(a - b) < 1.0 / 10000000
1
votes

I'm also reading the book, since we didn't get to std::abs, i did something like that:

int main()
{
double i1,i2;
while(cin>> i1 >> i2){

if (i1<i2) {
        if ((i2-i1)<=0.0000001)  cout << "Almost equal!"<<endl;
        else  cout << "the smaller value is: "<< i1 <<  " the larger value is: " << i2 <<endl;
}
if (i1>i2) {
        if ((i1-i2)<=0.0000001)  cout << "Almost equal!"<<endl;
        else  cout << "the smaller value is: "<< i2 <<  " the larger value is: " << i1 <<endl;
}


else if (i1==i2) cout << "the value : "<< i1 <<  " And the value : " << i2 << "  are equal!"<<endl;

}
}