2

I'm new in C, so I try to create a program that calculate the area of triangle as a start.

Calculating the area is easy when the triangle exists, however the validation of straight line is working partially.

Example:

A(0,-4) B(1,0) C(4,12) does not produce straight line error.

but A(4,12) B(1,0) C(0,-4) produce straight line error.

#include <stdio.h>
#include <math.h>

double square(double num){
    return (num*num);
}

int main()
{

    double x[5],y[5],a,b,c,angle,area;

    printf("Hello there! Calculating the area of triangle.\n");

    printf("Enter a coordinate A :\n");
    scanf("%lf,%lf",&x[0],&y[0]);

    printf("Enter another coordinate B :\n");
    scanf("%lf,%lf",&x[1],&y[1]);

    printf("Enter another coordinate C :\n");
    scanf("%lf,%lf",&x[2],&y[2]);

    // AB as base (a) , c is opposite side 

    a = sqrt( square((x[0]-x[1])) + square((y[0]-y[1])) );
    b = sqrt( square((x[0]-x[2])) + square((y[0]-y[2])) );
    c = sqrt( square(x[1]-x[2]) + square((y[1]-y[2])) );

    double num = (square(a)+square(b)-square(c))/(2*a*b);
    angle = acos(num);
    area = .5*a*b*sin(angle);

   //printf("%lf %lf %lf %lf %lf \n",a,b,c,num,angle);

    if (num == 1 || num ==-1){
        printf("That's a straight line.");
    }else{
        printf("Area of triangle is %lf\n",area);
    }

    return 0;

}
  • 3
    Three collinear points do form a degenerate triangle with area zero; IAC, you may want to look at [Is Floating Point Math Broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – ad absurdum Dec 15 '19 at 04:28
  • sometimes it does return 0 and nan. ok i'll into that – Muhammad Nazmi Dec 15 '19 at 05:08
  • 1
    You can get a more accurate length with `a = sqrt( square((x[0]-x[1])) + square((y[0]-y[1])) );` --> `a = hypot(x[0]-x[1], y[0]-y[1]);`. Easier to read too. – chux - Reinstate Monica Dec 15 '19 at 07:24

2 Answers2

3

You can use a different test, and perhaps a different area formula. If you use Heron's formula, then once you have the lengths of the sides a, b, and c, you can compute:

double p = (a + b + c)/2;
double area = sqrt(p*(p-a)*(p-b)*(p-c));

You can detect if the triangle is valid by checking that p is greater than each of the sides.

double p = (a + b + c)/2;
if ((p > a) && (p > b) && (p > c)) {
    double area = sqrt(p*(p-a)*(p-b)*(p-c));
    printf("Area of triangle is %lf\n", area);
} else {
    printf("I don't consider that a triangle.\n");
}

Try it online!

jxh
  • 69,070
  • 8
  • 110
  • 193
2

The problem in your code is double num = (square(a)+square(b)-square(c))/(2*a*b); gets evaluated to a number slightly larger than 1 in some cases. This can happen with floating point computations. In your case you can safely add if (num > 1) num = 1; after that line since cosine equation always will give you a value larger than 0 and less than 1 for triangles.

However there's a problem if two points overlap and a or b becomes zero. You will have to check for that and handle it as a special case if such input is expected by your code. (If two points overlap then they are collinear anyways. You can check the overlap by checking if any of a,b,c are zero)

Teshan Shanuka J
  • 1,448
  • 2
  • 17
  • 31
  • I suspect "slightly less than -1" can occur too. – chux - Reinstate Monica Dec 15 '19 at 07:26
  • @chux-ReinstateMonica Actually no. For any given triangle, `a+b > c` holds. Therefore `square(a)+square(b)-square(c)` will always be positive. The edge cases are `a+b = c` where the points are in a line. In that case the angle will be zero. When two points overlap, there's a problem since a division by zero can occur. – Teshan Shanuka J Dec 15 '19 at 07:31
  • 1
    That is a good geometry explanation, yet we are using FP math with all its impreciseness, sub-normals, infinities and rounding as compared to pure math. I see little loss insuring `fabs(num <= 1.0)` vs risking `NaN`. Note: `2*a*b` may be zero, even if `a` and `b` are not. – chux - Reinstate Monica Dec 15 '19 at 07:36
  • I agree with you. Since OP is a beginner, I didn't mention anything about the floating point comparisons. Here's a [link](https://stackoverflow.com/questions/9850663/comparing-same-float-values-in-c) if OP needs more insight on that. I acually use the following function in C++ for FP comparisons `template inline bool isAproxEqual(T x, T y) { return std::fabs(x - y) <= std::numeric_limits::epsilon(); }` – Teshan Shanuka J Dec 15 '19 at 07:41
  • `std::fabs(x - y) <= std::numeric_limits::epsilon()` takes the floating out of floating point. It does not fail when `x,y` are large and consecutive `double`s and always passes when `x,y` have small magnitudes. Such a test is only useful for a narrow mid-range of `double`. – chux - Reinstate Monica Dec 15 '19 at 07:47
  • thanks for the link, yes I have read that num might slightly bigger/lower than 1 and -1. i assume the coordinates no precise than 5 dp and round the num to 5dp to match 1/-1 and it works. i did also try using fabs(x-1.0f) < 0.1e-8 and it works too – Muhammad Nazmi Dec 15 '19 at 11:42