I'm a beginner in C and have this problem: I'm supposed to make an app where you insert the coordinates of a triangle's vertices, and then it prints details about its area, perimeter and most interesting of all, it's supposed to print its angles. The code is supposed to be written using the double tangent equation from Heron's formula. I've tried doing it using atan(), but I guess I should add +n to avoid going out of the domain. Don't know how though.
Here's the equation. And below is my code:
#include <stdio.h>
#include <math.h>
#define PI (4. * atan(1))
int main() {
// Defining floats
float xa, ya, xb, yb, xc, yc, s, P, a, b, c, x, y, z, alphadeg, alpharad, betadeg, betarad, gammadeg, gammarad;
// Inserting coordinates of each points
printf("Insert the first point's coordinates (a space should be between the X and Y coordinate):\n");
scanf("%f %f", &xa, &ya);
printf("Insert the second point's coordinates (a space should be between the X and Y coordinate):\n");
scanf("%f %f", &xb, &yb);
printf("Insert the third point's coordinates (a space should be between the X and Y coordinate):\n");
scanf("%f %f", &xc, &yc);
// Calculating and printing length of each side
printf("Distance between point 1 and 2: %f\n", sqrt(pow(xa - xb, 2) + pow(ya - yb, 2)));
printf("Distance between point 1 and 3: %f\n", sqrt(pow(xa - xc, 2) + pow(ya - yc, 2)));
printf("Distance between point 2 and 3: %f\n", sqrt(pow(xb - xc, 2) + pow(yb - yc, 2)));
// Defining each side
a = sqrt(pow(xa - xb, 2) + pow(ya - yb, 2));
b = sqrt(pow(xa - xc, 2) + pow(ya - yc, 2));
c = sqrt(pow(xb - xc, 2) + pow(yb - yc, 2));
// Defining s as the parameter from Heron's formula
s = ((a + b + c) / 2);
// Defining P as the area from Heron's formula
P = sqrt(s * (s - a) * (s - b) * (s - c));
// Printing the area and perimeter of the triangle
printf("The area of your triangle is %f\n", P);
printf("The perimeter of your triangle is %f\n", a + b + c);
// Angles
/*
tan(alpha/2)=sqrt(((P-b)*(P-c))/(P*(P-a)));
tan(beta/2)=sqrt(((P-a)*(P-c))/(P*(P-b)));
tan(gamma/2)=sqrt(((P-a)*(P-a))/(P*(P-c)));
Let
x = tan(alpha/2)
y = tan(beta/2)
z = tan(gamma/2)
*/
x = sqrt(((P - b) * (P - c)) / (P * (P - a)));
y = sqrt(((P - a) * (P - c)) / (P * (P - b)));
z = sqrt(((P - a) * (P - b)) / (P * (P - c)));
alphadeg = (atan(x)) * 360 / PI;
betadeg = (atan(y)) * 360 / PI;
gammadeg = (atan(z)) * 360 / PI;
alpharad = 2 * (atan(x));
betarad = 2 * (atan(y));
gammarad = 2 * (atan(z));
printf("The value of the alpha angle is %0.3f\n", alphadeg);
printf("The value of the beta angle is %0.3f\n", betadeg);
printf("The value of the gamma angle is %0.3f\n", gammadeg);
printf("%f = %f", PI, (alpharad + betarad + gammarad));
return 0;
}
The issue is caused by a misunderstanding of the mathematical formulas.
// That's the formula to calculate the semi perimeter of a triangle
// given the length of its sides a, b and c.
s = ((a + b + c) / 2);
// Defining P as the area from Heron's formula
P = sqrt(s * (s - a) * (s - b) * (s - c));
The name P, here, is misleading (s too, actually) and not only because they are one-letter variable names. In the following formulas, the OP uses P instead of the semi-perimeter:
x = sqrt(((P - b) * (P - c)) / (P * (P - a)));
// ^ ^ ^ ^ You should use 's' instead.
You can consider to add epsilon like below:
float EPSILON = 0.1
x = sqrt(((P-b)*(P-c))/(EPSILON+P*(P-a)));
Related
I have been trying to implement the optimized rasterizer outlined in this blog: https://fgiesen.wordpress.com/2013/02/10/optimizing-the-basic-rasterizer/.
The naive approach outlined in his prior blog post https://fgiesen.wordpress.com/2013/02/08/triangle-rasterization-in-practice/, calculates the determinants (for barycentric weights) at each pixel. But his optimized version takes advantage of the fact that for three points a, b, c, the determinant function
(b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x)
can be rewritten as
A * c.x + B * c.y + C
for
A = (a.y - b.y), B = (b.x - a.x), C = a.x * b.y - a.y * b.x.
Since during traversal, the points a, b are two points on the triangle, c is the only point whose values change.
For any edge function E which outputs the weight for the corresponding triangle partition made by it and the point c, we can express an x difference and y difference in discrete steps.
E(c.x, c.y) = A * c.x + B * c.y + C
so
E(c.x + 1, c.y) - E(c.x, c.y) = A, and E(c.x, c.y + 1) - E(c.x, c.y) = B
So at each iteration instead of recalculating the determinant, we can just find the three determinants for the first c, and then increment them the A or B which corresponds to their edge.
I'm currently trying to implement this in my own rasterizer, but I quickly noticed an issue with the formula. My triangles are fed to the draw function in screen space, so a low y value means high up whereas in vector space it means low down. I thought I would account for this by multiplying every y value in the formula by -1.
This gave me the following formula for the determinant of a, b, c:
(b.x - a.x) * (a.y - c.y) - (a.y - b.y) * (c.x - a.x)
From which I derived the following A, B, C:
A = b.y - a.y, B = a.x - b.x, C = b.x * a.y - a.x * b.y
In my tests, using this new determinant formula (calculated at every pixel) works fine. And for the first point c in traversal, it is equivalent to
A * c.x + B * c.y + C
But as it continues traversing along the triangle's bounding box, the step incremented determinant values go out of sync with the raw calculated determinant values. Somehow this means that the step sizes A and B are faulty-- which makes no sense to me.
The only two causes of this problem I can think of are either I calculated A B and C incorrectly, or I am not mapping from vector space to screen space in a way that preserves area or orientation.
But just in case, here is all of my code for the rasterizer:
helpers
typedef float* point_t;
typedef float* triangle_t;
typedef struct edge {
point_t tail, tip;
float step_x, step_y;
int is_top_left;
} edge_t;
/* ... */
/* tail is the begining of the edge (i.e a), tip is the end of the edge (b) and c is variable */
static float init_edge(edge_t* edge, point_t tail, point_t tip, point_t origin) {
edge->tail = tail;
edge->tip = tip;
edge->is_top_left = is_top_left(tail, tip);
float A = tip[1] - tail[1];
float B = tail[0] - tip[0];
float C = tip[0] * tail[1] - tail[0] * tip[1];
/* step sizes */
edge->step_x = A;
edge->step_y = B;
/* edge function output at origin */
return A * origin[0] + B * origin[1] + C;
}
static float det(point_t a, point_t b, point_t c) {
return (b[0] - a[0]) * (a[1] - c[1]) - (a[1] - b[1]) * (c[0] - a[0]);
}
draw_triangle
void draw_triangle(sr_pipeline_t* pipeline, triangle_t triangle) {
/* orient triangle ccw */
point_t v0 = (point_t)malloc(sizeof(float) * pipeline->num_attr);
point_t v1 = (point_t)malloc(sizeof(float) * pipeline->num_attr);
point_t v2 = (point_t)malloc(sizeof(float) * pipeline->num_attr);
memcpy(v0, triangle, sizeof(float) * pipeline->num_attr);
memcpy(v1, triangle + pipeline->num_attr, sizeof(float) * pipeline->num_attr);
memcpy(v2, triangle + (2 * pipeline->num_attr), sizeof(float) * pipeline->num_attr);
orient_ccw(&v0, &v1, &v2);
/* find bounding box */
float min_x = /* ... */;
float min_y = /* ... */;
float max_x = /* ... */;
float max_y = /* ... */;
/* store current point */
point_t p = (point_t)calloc(pipeline->num_attr, sizeof(float));
p[0] = min_x;
p[1] = min_y;
/* grab edge information */
edge_t e01, e12, e20;
float w0 = init_edge(&e12, v1, v2, p);
float w1 = init_edge(&e20, v2, v0, p);
float w2 = init_edge(&e01, v0, v1, p);
/* rasterize */
for (p[1] = min_y; p[1] <= max_y; p[1]++) {
for (p[0] = min_x; p[0] <= max_x; p[0]++) {
/* determinant calculated at every step (I suspect these are correct) */
float s0 = det(v1, v2, p);
float s1 = det(v2, v0, p);
float s2 = det(v0, v1, p);
if ( (s0 >= 0) && (s1 >= 0) && (s2 >= 0) ) {
draw_point(pipeline, p);
}
w0 += e12.step_x;
w1 += e20.step_x;
w2 += e01.step_x;
}
w0 += e12.step_y;
w1 += e20.step_y;
w2 += e01.step_y;
}
free(v0);
free(v1);
free(v2);
free(p);
}
Code and functions that I have omitted I have verified work correctly.
To reiterate, my question is why are the values w0, w1, w2 not the same as s0, s1, s2 as they should be?
Any help is appreciated, thank you!
Rather than multiply every y value in the formula by -1, replace them with (top - y).
#include <math.h>
#include <stdio.h>
main() {
int a, b, c, x, x1, x2;
printf("enter the values of a,b,c:");
scanf("%d%d%d", &a, &b, &c);
printf("The quadratic equation is %d*pow(x,2)+%d*x+%d=0", a, b, c);
if (pow(b, 2) - 4 * a * c >= 0) {
x1 = (-b + sqrt(pow(b, 2) - 4 * a * c)) / 2 * a;
x2 = (-b - sqrt(pow(b, 2) - 4 * a * c)) / 2 * a;
printf("the roots of the equation are x1=%d,x2=%d", x1, x2);
}
else
printf("roots of the equation in the form of x+iy and x-iy");
return 0;
}
Is this code alright for the given question, i had a bit confusion at that printing imaginary roots. could you please help
Use proper main prototype.
Use floating point numbers instead of integers
pow(b,2) == b*b
/ 2 * a -> / (2 * a)
int main(void) {
double a, b, c, x, x1, x2;
printf("enter the values of a,b,c:");
if(scanf("%lf %lf %lf", &a, &b, &c) != 3) { /* handle error */}
printf("\nThe quadratic equation is %f*x^2+%f*x+%f=0\n", a, b, c);
if (b*b - 4 * a * c >= 0) {
x1 = (-b + sqrt(b*b - 4 * a * c)) / (2 * a);
x2 = (-b - sqrt(b*b - 4 * a * c)) / (2 * a);
printf("the roots of the equation are x1=%f,x2=%f\n", x1, x2);
}
else
{
double r = -b / (2*a);
double z = sqrt(fabs(b*b - 4 * a * c));
printf("the roots of the equation are x1 = %f + i%f, x2 = %f - i%f", r,z,r,z);
}
}
https://gcc.godbolt.org/z/Ys1s8bWY7
It's just a super basic program that finds the roots of a quadratic function. After the calculations the output for the solutions shows "-nanloat" instead of the actual answer. Here's the problematic code:
/*If the polynomial has real solutions, calculate and print them */
if (nRSolutions > 0){
sol = ((-b + sqrt(pow(2.0,b) + 4 * a * c)) / (2.0 * a));
printf("La solución a la ecuación es %float", sol);
/*That means "the solution to the equation is (float)"*/
}
if (nRSolutions = 2){
sol2 = ((-b - sqrt(pow(2.0,b) + 4 * a * c)) / (2.0 * a));
printf("La segunda solución a la ecuación es %float", sol2);
/*That means "the second solution to the equation is (float)"*/
}
Here's the variable declaration in case that might be part of the problem, but I really don't think that's it.
/* d = discriminant value; sol = solution; sol2 = second solution*/
float a, b, c, d, sol, sol2;
int nRSolutions;
nRSolutions = 0;
They are all defined afterwards.
Here's your problem:
if (nRSolutions = 2){
You're not comparing but assigning, and since the value you're assigning is nonzero the condition will always be true. You instead want:
if (nRSolutions == 2){
Wrong equation (in addition to issue identified by#dbush). See Quadratic formula:
// sqrt(pow(2.0,b) + 4 * a * c))
sqrt(pow(b, 2.0) - 4 * a * c))
// ^^^^^^^^^^^ ^
Even better as
double discriminate = b*b - 4*a*c;
if (discriminate < 0.0) TBD_code();
else sol = (-b + sqrt(discriminate)) / (2.0 * a);
Tip for improve precision: minimize subtraction cancellation
double discriminate = b*b - 4*a*c;
if (discriminate < 0.0) TBD_code();
// Add or subtract such that the result is larger
if (b < 0) sol = (-b + sqrt(discriminate)) / (2.0 * a);
else sol = (-b - sqrt(discriminate)) / (2.0 * a);
// We know a*sol*sol2 == c
sol2 = sol ? 0.0 : c/a/sol;
I was given a problem to write a C program which would solve the equation ax2+bx+c=0, where a, b and c are coefficients with double type. Any of the coefficients may be zero. In this problem it is unclear to me how to handle the double variables.
Here is my code. As for now, I know that my program can't distinguish between two roots and infinitely many roots. It also doesn't detect the "linear equation situation". How can I make it detect an infinite number of solutions? I was also advised in the comments to calculate the root with the minus before the discriminant if b > 0 and then use the Viet's theorem. I understand that it is because it is always more accurate to sum two numbers. I also guess I should do the exact opposite with b < 0. But what if b == 0 ? In this case, the program will not do anything. Or should I just include b == 0 in b < 0 and have b <= 0 ?
#include <stdio.h>
#include <math.h>
#include <float.h>
int main() {
double a, b, c, x1, x2;
scanf("%lf", &a);
scanf("%lf", &b);
scanf("%lf", &c); // just reading variables
//ax^2+bx+c=0
if ((b * b - 4 * a * c) < 0) {
printf("no");
} else {
x1 = (-b + sqrt(b * b - 4 * a * c)) / (2 * a); //calculating roots
x2 = (-b - sqrt(b * b - 4 * a * c)) / (2 * a);
if ((fabs((a * x1 * x1 + b * x1 + c)) < DBL_EPSILON) & (fabs((a * x2 * x2 + b * x2 + c)) < DBL_EPSILON)) { //plugging the roots in
if (fabs((x1 - x2)) < DBL_EPSILON) { //checking if the roots are equal
printf("%lf", &x1); // if they are equal, we print only one of them
} else {
printf("%lf", &x1); // if they are not equal, we print both.
printf("\n %lf", &x2);
}
} else { // if there are no two valid roots
if ((fabs((a * x1 * x1 + b * x1 + c)) < DBL_EPSILON)) // we try to find one root.
printf("%lf", &x1);
if (fabs((a * x2 * x2 + b * x2 + c)) < DBL_EPSILON)
printf("%lf", &x2);
if ((fabs((a * x1 * x1 + b * x1 + c)) > DBL_EPSILON) & (fabs((a * x2 * x2 + b * x2 + c)) > DBL_EPSILON)) // if both of the plugged roots don't satisfy the equation
printf("no");
}
}
return 0;
}
Solve quadratic equation when coefficients may be 0
How can I make it detect an infinite number of solutions?
When a==0 && b == 0 && c == 0.
No DBL_EPSILON needed really anywhere in this code. See also #Eric Postpischil.
But what if b == 0 ?
if (b == 0) { // y = a*x*x + c
if (a) {
double dd = -c/a;
if (dd >= 0) {
double d = sqrt(d);
printf_roots("+/- roots", d,-d);
} else {
printf_roots("Complex roots", NAN, NAN); // Note NAN may not exist
}
} else if (c) { // y = 0*x*x + c, c != 0
printf_roots("No roots", NAN, NAN);
} else { // y = 0*x + 0
printf_roots("Infinite roots", -HUGE_VAL, HUGE_VAL);
}
Or should I just include b == 0 in b < 0 and have b <= 0 ?
Unless the coding goal requires a special output when b==0, I would only vector code on b==0 as a subtest when a==0 occurred.
if (a==0) {
if (b == 0) {
The quadric equation, like much FP code, can readily overflow and hit 0, both cases losing all precision.
Consider the code below: the unnecessary subtraction may cause overflow or truncation to 0 versus the second which may not. It is dependent on many things.
if ((b * b - 4 * a * c) < 0)
//
if (b * b < 4 * a * c)
Further, C allows various calculations to occur using wider math. Research FLT_EVAL_METHOD. Because of this, to prevent sqrt(value_less_than_0), code should calculate the discriminate and then test the object x that is going to be applied to sqrt(x).
//if ((b * b - 4 * a * c) < 0) {
// printf("no");
//} else {
// x1 = (-b + sqrt(b * b - 4 * a * c))
double discriminate = b * b - 4 * a * c;
if (discriminate < 0) {
printf("no");
} else {
double d = sqrt(discriminate);
x1 = (-b + d)
As to the idea of "calculate the root with the minus before the discriminant if b > 0 and then use the Viet's theorem", I'd suggest for improved retained precision the below which does not subtract like signed values.
double d = sqrt(discriminate);
// Note x1*x2 = c/a
if (b < 0) {
x2 = (-b + d)/(2*a);
x1 = c/a/x2;
} else {
x1 = (-b - d)/(2*a);
x2 = c/a/x1;
}
printf_roots("2 roots", x1, x2);
Notes on printf("%lf", &x1);. You are not compiling with all warnings enabled. Save time - enable them. Should be printf("%lf", x1); No &.
Further double is floating point. For FP code development use "%e", "%a" or"%g" to full see significant information.
printf("%g\n", some_double);
// or better
printf("%.*e\n", DBL_DECIMAL_DIG -1, some_double);
Since division by zero is not allowed, you have to split the problem into 4 cases :
a != 0:
this is case you treated in your code.
a == 0 && b != 0 :
This is a linear equation where the solution is x = -c/b
a == 0 && b == 0 && c != 0 : There's no possible value for x.
In this last case, a, b and c are equals to 0 : there's infinitly many solutions for x.
EDIT: comparisons with epsilon removed since they seem to be useless
There are some problems in your code:
you should check the return values of scanf() to avoid undefined behavior on invalid input.
you should use local variables for intermediary results to improve code readability
your printf statements are incorrect: you should pass the values of the double variables instead of their addresses: printf("%lf", &x1); should read:
printf("%f", x1);
Regarding the degenerate cases, you should just test those before trying to resolve the second degree equation.
Here is a corrected version:
#include <stdio.h>
#include <math.h>
int main() {
double a, b, c, delta, x1, x2;
if (scanf("%lf%lf%lf", &a, &b, &c) != 3) {
printf("invalid input\n");
return 1;
}
if (a == 0) {
// not a quadratic equation
if (b != 0) {
printf("one solution: %g\n", -c / b);
} else {
if (c != 0) {
printf("no solution\n");
} else {
printf("all real values are solutions\n");
}
}
} else {
delta = b * b - 4 * a * c;
if (delta < 0) {
printf("no real solution\n");
} else
if (delta == 0) {
printf("one double solution: %g\n", -b / (2 * a));
} else {
x1 = (-b + sqrt(delta)) / (2 * a);
x2 = (-b - sqrt(delta)) / (2 * a);
printf("two solutions: %g, %g\n", x1, x2);
}
}
return 0;
}
So I derived a rotation function like this:
I want to rotate (a, b, c) around the x axis
the value of a will not change
this is equivalent to rotating (b, c) around the origin in a 2d map
for a 2d map in polar coordinates, rotating d degrees is as simple as:
θ = θ + d
for a point P(x, y), x = Rcos(θ) and y = Rsin(θ)
so let Q be the point after rotation, then Q = (Rcos(θ + d), Rsin(θ + d))
since R2 = x2 + y2 and θ = arctan(y/x):
Q = (sqrt(x2 + y2) * cos(arctan(y/x) + d, sqrt(x2 + y2) * sin(arctan(y/x) + d)
I then made a C function that given a coordinate: a and rot_amount (usually 1) it would rotate my coordinate for me.
static void xrotate_coor(t_coor *a, int rot_amount)
{
double d;
double e;
d = a->y;
e = a->z;
if (e == 0 && d == 0)
return ;
if (d == 0)
{
a->y = sqrt(d * d + e * e) * cos(atan(INFIN) + rot_amount * M_PI / 50);
a->z = sqrt(d * d + e * e) * sin(atan(INFIN) + rot_amount * M_PI / 50);
return ;
}
a->y = sqrt(d * d + e * e) * cos(atan(e / d) + rot_amount * M_PI / 50);
a->z = sqrt(d * d + e * e) * sin(atan(e / d) + rot_amount * M_PI / 50);
}
INFIN is a macro I set to 999999.
I am not sure if it is correct though since using this formula the shape I am rotating is getting deformed so I feel like there is a flaw in my logic somewhere...
You are experiencing the accumulation of errors in the calculations. This is caused by the nature of how numbers are represented in computers.
The typical way to handle this problem in computer graphics is to keep the object's coordinates fixed and translate them to the position required for the frame being rendered. In your case, this would mean that rather than progressively rotating the object, leave the object in its original position and simply calculate the translation to the current angle around the X-axis based on where it should currently be displayed.
In other words, if you are translating 360 degrees total 20 degrees at a time, display the translated coordinates at 20 degrees in the first iteration and the translated coordinates at 40 degrees in the second iteration rather than actually translating 20 degrees each time.
... the shape I am rotating is getting deformed ...
atan(e / d) loses the 4 quadrant nature of a->y, a->z;. Consider that with OP's code, if the y,z are negated, the same result ensues. #Nominal Animal
d = -(a->y);
e = -(a->z);
...
atan(e / d)
Instead use a 4 quadrant arctangent.
double atan2(double y, double x);
The atan2 functions compute the value of the arc tangent of y/x, using the signs of both arguments to determine the quadrant of the return value. A domain error may occur if both arguments are zero.
Other suggested improvements below too.
#include <math.h>
static void xrotate_coor(t_coor *a, int rot_amount) {
double d = a->y;
double e = a->z;
double r = hypot(d, e); // vs. sqrt(d * d + e * e)
if (r) {
double angle = atan2(e, d);
angle += rot_amount * (M_PI / 50);
a->y = r * cos(angle);
a->z = r * sin(angle);
}
}