c++sqrtcmathpythagorean

Specific right-angled Triangles are not being recognized as right-angled in Cpp


I have to take the coordinates of the vertices of a triangle from the user and tell if it is a right-angled triangle or not. I'm using Pythagoras Theorem to Find out i.e. h * h = b * b + p * p

But surprisingly this doesn't work for some specific right-angled triangles. Here is one such Triangle:

Vertex A: (x, y) = (1, 3)

Vertex B: (x, y) = (1, 1)

Vertex C: (x, y) = (5, 1)

It calculates perfectly, which I figured out by printing the calculation, but still doesn't work.

Then I tried by using sqrt() function from the cmath library this way: h = sqrt(b * b + p * p)

Logically it is the same, but it worked.

I want to understand, why the earlier method is not working?

Here is a simplified version of My Code:

#include <iostream>
#include <cmath>

using namespace std;

class Vertex {

    double x, y;

public:
    void take_input(char obj) {
        cout << endl << "   Taking Coordinates of Vertex " << obj << ": " << endl;

        cout << "       Enter the x component: ";
        cin >> x;
        cout << "       Enter the y component: ";
        cin >> y;
    }

    double distance(Vertex p) {
        double dist = sqrt((x-p.x)*(x-p.x) + (y-p.y)*(y-p.y));

        return dist;
    }
};

class Triangle {
    Vertex a, b, c;

public:

    void take_inp(string obj) {
        cout << endl << "Taking Vertices of the Triangle " << obj << ": " << endl;
        cout << "   Verteces should be in a counter clockwise order (as per convention)." << endl;

        a.take_input('A');
        b.take_input('B');
        c.take_input('C');
    }

    void is_rt_ang() {

        double h = a.distance(c)*a.distance(c);
        double bp = a.distance(b)*a.distance(b) + b.distance(c)*b.distance(c);

        /*
            // Strangely this attempt works which is logically the same: 
            double h = a.distance(c);
            double bp = sqrt(a.distance(b)*a.distance(b) + b.distance(c)*b.distance(c));
        */

        if (h == bp) {
            cout << "Angle is 90" << endl;
            cout << h << " = " << bp << endl;
            cout << "It is Right-Angled" << endl;
        }
        else {
            cout << "Angle is not 90!" << endl;
            cout << h << " != " << bp << endl;
            cout << "It is Not a Right-Angled" << endl;
        }
    }
};

int main()
{
    Triangle tri1, tri2;

    tri1.take_inp("tri1");

    tri1.is_rt_ang();

    return 0;
}

Solution

  • The line

    double dist = sqrt((x-p.x)*(x-p.x) + (y-p.y)*(y-p.y));
    

    in the Vertex::distance method gives you an approximation of a square root which is rarely going to coincide with an exact answer. This is because most real numbers can't be represented in floating point arithmetic.

    But in given code sample you can make do without sqrt. Replace Vertex::distance method with a method

     double distance_square(Vertex p) {
        double dist_square = (x-p.x)*(x-p.x) + (y-p.y)*(y-p.y);
        return dist_square;
    }
    

    and call it like this in Triangle::is_rt_ang:

        double h = a.distance_square(c);
        double bp = a.distance_square(b) + b.distance_square(c);
    

    This solution is still flawed because floating-point multiplication is also a subject to rounding errors. But if it is guaranteed that you are going to work only with integer coordinates, you can replace all doubles in your code with ints and for them there is no problem with multiplication (besides possibly going out of bounds for large numbers).

    EDIT: Also a comment on printing

    It calculates perfectly, which I figured out by printing the calculation, but still doesn't work.

    When you print doubles you need to set precision manually in order to avoid rounding. If in your code I replace a line

    cout << h << " != " << bp << endl;
    

    with

    cout << std::setprecision(std::numeric_limits<double>::digits10) << std::fixed << h << " != " << bp << endl;
    

    then for example triangle from the question I get the output

    Angle is not 90!
    20.000000000000004 != 20.000000000000000
    It is Not a Right-Angled

    For this to compile you will need to add #include <limits> and #include <iomanip>.