Omer Rudnick
Omer Rudnick

Reputation: 61

Trying to determine if a triangle is a right triangle in C using the Epsilon rule

int IsRightTriangle(float side1, float side2, float side3)
{
    if (side3*side3-(side1*side1+side2*side2) <= 0.05 || side3*side3-(side1*side1+side2*side2) >= -0.05) {
        return 1;
    }
    else if (side1*side1-(side3*side3+side2*side2) <= 0.05 || side1*side1-(side3*side3+side2*side2) >= -0.05) {
        return 1;
    }
    else if (side2*side2-(side3*side3+side1*side1) <= 0.05 || side2*side2-(side3*side3+side1*side1) >= -0.05) {
        return 1;
    }
    else 
        return 0;
}

I have tried multiple iterations of this code, and they all got results similar to this:


Running test: IsRightTriangle(edge1=15.00, edge2=27.00, edge3=29.55)  --  Passed
Running test: IsRightTriangle(edge1=21.02, edge2=19.00, edge3=9.00)  --  Failed

Upvotes: 1

Views: 257

Answers (1)

chux
chux

Reputation: 153527

What am I doing wrong?

I'd expect && instead of || as the compare needs to meet both conditions to be a "right" triangle.

Think of

if (side3*side3-(side1*side1+side2*side2) <= 0.05 || side3*side3-(side1*side1+side2*side2) >= -0.05) { 
    return 1;
}

as

double d = side3*side3-(side1*side1+side2*side2);
if (d <= 0.05 || d >= -0.05) {
    return 1;
}

d <= 0.05 || d >= -0.05 is always true (unless sides had a not-a-number).
Certain it should use d <= 0.05 && d >= -0.05.
Other issues exist too.


Trying to determine if a triangle is a right triangle

Suggested alternative algorithm:

  1. Determine the the side with the largest magnitude squared - the candidate hypotenuse squared. This negates the need for square root and absolute value.

  2. Sum the other 2 squares.

  3. Relatively compare the two for nearness to 1.0 (a right triangle).
    Code is dealing with floating point values.
    IsRightTriangle(15.00 , 27.00 , 29.55) should get the same result as
    IsRightTriangle(15.00e10 , 27.00e10 , 29.55e10) and as
    IsRightTriangle(15.00e-10, 27.00e-10, 29.55e-10).

Example: Lightly tested sample code:

int IsRightTriangle(float side1, float side2, float side3) {
  double sq[3];
  sq[0] = 1.0 * side1 * side1; // Use double math for extra precision and range.
  sq[1] = 1.0 * side2 * side2;
  sq[2] = 1.0 * side3 * side3;

  if (sq[1] < sq[2]) {
    swap(&sq[1], &sq[2]);
  }
  if (sq[0] < sq[1]) {
    swap(&sq[0], &sq[1]);
  }
  // sq[0] is now the largest.

  double hypotenuse = sq[0];
  double sum_of_smaller2 = sq[1] + sq[2];

  if (hypotenuse == 0.0) {
    return 1; // Degenerate case, all sides 0.
  }

  // How close to 1.0 is sum_of_smaller2/hypotenuse?
  #define Epsilon 0.05
  // Use the square as the we are testing the square of magnitudes.
  #define Epsilon2 (Epsilon * Epsilon)
  double ratio = sum_of_smaller2 / hypotenuse;
  return (1.0 - Epsilon2 <= ratio) && (ratio <= 1.0 + Epsilon2);
}

Notes:

  • double or float? OP is using float arguments, yet double constants and discusses double functions like sqrt() instead of sqrtf().

  • abs() is an integer function and has no place here. Instead discuss fabs(), fabsf().

Upvotes: 2

Related Questions