add logic for pure quadratics

This commit is contained in:
hugogogo
2026-05-14 23:11:37 +02:00
parent 840f5bcfdf
commit 6c6accc289
7 changed files with 301 additions and 51 deletions

View File

@@ -124,6 +124,13 @@ typedef enum
DELTA_MINUS = -1,
} e_delta_sign;
typedef enum
{
RADICAND_ZERO = 0,
RADICAND_PLUS = 1,
RADICAND_MINUS = -1,
} e_radicand_sign;
typedef struct
{
double a; // a in "ax + b"
@@ -136,8 +143,8 @@ typedef struct
double a; // a in "ax² + bx + c"
double b; // b in "ax² + bx + c"
double c; // c in "ax² + bx + c"
e_delta_sign delta_sign; // DELTA_PLUS or DELTA_MINUS or DELTA_ZERO
double delta; // Δ == b² - 4ac
e_delta_sign delta_sign; // DELTA_PLUS or DELTA_MINUS or DELTA_ZERO
double delta_absolute; // |Δ|
double delta_sqrt; // √|Δ|
double left_term; // double (-b / 2a)
@@ -149,13 +156,29 @@ typedef struct
int right_term_denominator; // 2a / gcd
} s_solution_degree_2;
typedef struct
{
double a; // a in "ax² + c"
double c; // c in "ax² + c"
double radicand; // x² = -c/a
e_radicand_sign radicand_sign; // RADICAND_PLUS or RADICAND_MINUS or RADICAND_ZERO
double radicand_absolute; // |radicand|
double radicand_sqrt; // √|radicand|
double numerator_sqrt; // √a
bool numerator_sqrt_is_int; // false if √a is a double
double denominator_sqrt; // √c
bool denominator_sqrt_is_int; // false if √c is a double
} s_solution_degree_2_pure;
typedef struct
{
int degree;
bool is_quadratic_pure;
union
{
s_solution_degree_1 solution_degree_1;
s_solution_degree_2 solution_degree_2;
s_solution_degree_2_pure solution_degree_2_pure;
};
} s_solution;
@@ -166,6 +189,10 @@ void solve(const s_polynom *polynom, s_solution *solution);
*/
bool is_nearly_equal_zero(double num);
bool has_decimal_part(double num);
bool any_has_decimal_part(double *num, size_t len);
int gcd_int(int a, int b);
int reduce_fraction(double *numerator, double *denominator);
/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* UTILS/ERRORS.C
@@ -183,6 +210,7 @@ const char *token_tag_to_str(e_token_tag tag);
const char *term_position_to_str(e_term_position pos);
const char *term_sign_to_str(e_term_sign sign);
const char *delta_sign_to_str(e_delta_sign sign);
const char *radicand_sign_to_str(e_radicand_sign enum_value);
/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* UTILS/PRINT_DEBUG.C

View File

@@ -2,12 +2,98 @@
#include "computorv1.h"
/**
* DEGREE 1
*/
static void print_solution_degree_1(s_solution_degree_1 solution)
{
ft_printf("The solution is:\n");
printf("%g\n", solution.solution);
}
/**
* DEGREE 2 PURE
*/
static void print_solution_pure_radicand_zero()
{
ft_printf("Radicant is equal to zero, the solution is:\n");
printf("0\n");
}
static void print_solution_pure_radicand_positiv(s_solution_degree_2_pure solution)
{
double numerator;
double denominator;
ft_printf("Radicant is strictly positive, the two solutions are:\n");
if (solution.numerator_sqrt_is_int && solution.denominator_sqrt_is_int)
{
numerator = solution.numerator_sqrt;
denominator = solution.denominator_sqrt;
reduce_fraction(&numerator, &denominator);
printf("%g/%g\n", numerator, denominator);
printf("-%g/%g\n", numerator, denominator);
}
else if (solution.numerator_sqrt_is_int)
{
printf("%g/√(%g)\n", solution.numerator_sqrt, solution.c);
printf("-%g/√(%g)\n", solution.numerator_sqrt, solution.c);
}
else if (solution.denominator_sqrt_is_int)
{
printf("√(%g)/%g\n", solution.a, solution.denominator_sqrt);
printf("-√(%g)/%g\n", solution.a, solution.denominator_sqrt);
}
else
{
numerator = solution.numerator_sqrt;
denominator = solution.denominator_sqrt;
reduce_fraction(&numerator, &denominator);
printf("√(%g/%g)\n", numerator, denominator);
printf("-√(%g/%g)\n", numerator, denominator);
}
}
static void print_solution_pure_radicand_negativ(s_solution_degree_2_pure solution)
{
double numerator;
double denominator;
ft_printf("Radicant is strictly negative, the two complex solutions are:\n");
if (solution.numerator_sqrt_is_int && solution.denominator_sqrt_is_int)
{
numerator = solution.numerator_sqrt;
denominator = solution.denominator_sqrt;
reduce_fraction(&numerator, &denominator);
printf("i%g/%g\n", numerator, denominator);
printf("-i%g/%g\n", numerator, denominator);
}
else if (solution.numerator_sqrt_is_int)
{
printf("i%g/√(%g)\n", solution.numerator_sqrt, solution.c);
printf("-i%g/√(%g)\n", solution.numerator_sqrt, solution.c);
}
else if (solution.denominator_sqrt_is_int)
{
printf("i√(%g)/%g\n", solution.a, solution.denominator_sqrt);
printf("-i√(%g)/%g\n", solution.a, solution.denominator_sqrt);
}
else
{
numerator = solution.a;
denominator = solution.c;
reduce_fraction(&numerator, &denominator);
printf("i√(%g/%g)\n", numerator, denominator);
printf("-i√(%g/%g)\n", numerator, denominator);
}
}
/**
* DEGREE 2
*/
static void print_solution_delta_zero(s_solution_degree_2 solution)
{
ft_printf("Discriminant is equal to zero, the solution is:\n");
@@ -59,7 +145,9 @@ static void print_solution_delta_negativ(s_solution_degree_2 solution)
void print_solution(s_solution *solution)
{
s_solution_degree_2 solution_d2;
s_solution_degree_2_pure solution_d2_pure;
e_delta_sign delta_sign;
e_radicand_sign radicand_sign;
// degree 1
@@ -67,7 +155,20 @@ void print_solution(s_solution *solution)
{
return print_solution_degree_1(solution->solution_degree_1);
}
else if (solution->degree == 2)
else if (solution->degree == 2 && solution->is_quadratic_pure)
{
solution_d2_pure = solution->solution_degree_2_pure;
radicand_sign = solution_d2_pure.radicand_sign;
if (radicand_sign == RADICAND_ZERO)
print_solution_pure_radicand_zero();
else if (radicand_sign == RADICAND_PLUS)
print_solution_pure_radicand_positiv(solution_d2_pure);
else if (radicand_sign == RADICAND_MINUS)
print_solution_pure_radicand_negativ(solution_d2_pure);
else
stop_errors("radicand sign is wrong : '%i' , radicand : '%g'", solution_d2_pure.radicand_sign, solution_d2_pure.radicand);
}
else if (solution->degree == 2 && !solution->is_quadratic_pure)
{
solution_d2 = solution->solution_degree_2;
delta_sign = solution_d2.delta_sign;

View File

@@ -32,36 +32,6 @@ static double positiv_zero(double num)
return num;
}
static int has_decimal_part(double num)
{
return (num != (int)num);
}
static bool any_has_decimal_part(double *num, size_t len)
{
while (len > 0)
{
if (has_decimal_part(num[len - 1]))
return true;
len--;
}
return false;
}
// find GCD of two integers using euclidean algorithm
static int gcd_int(int a, int b)
{
int tmp;
while (b != 0)
{
tmp = b;
b = a % b;
a = tmp;
}
return abs(a);
}
static void solve_degree_1(s_solution_degree_1 *solution, double a, double b)
{
solution->a = a;
@@ -120,6 +90,28 @@ static void solve_degree_2(s_solution_degree_2 *solution, double a, double b, do
solution->left_term_denominator = (a * 2) / gcd;
}
static void solve_degree_2_pure(s_solution_degree_2_pure *solution, double a, double c)
{
double radicand;
solution->a = a;
solution->c = c;
radicand = -c / a;
solution->radicand_sign = ft_fsign(radicand); // RADICAND_PLUS or RADICAND_MINUS or RADICAND_ZERO
solution->radicand_absolute = ft_fabs(radicand); // |radicand|
solution->radicand_sqrt = ft_sqrt(solution->radicand_absolute, DOUBLE_PRECISION); // √|radicand|
/**
* SQARE ROOTS
*/
solution->numerator_sqrt = ft_sqrt(a, DOUBLE_PRECISION);
solution->numerator_sqrt_is_int = !has_decimal_part(solution->numerator_sqrt);
solution->denominator_sqrt = ft_sqrt(c, DOUBLE_PRECISION);
solution->denominator_sqrt_is_int = !has_decimal_part(solution->denominator_sqrt);
}
void solve(const s_polynom *polynom, s_solution *solution)
{
double power2;
@@ -138,7 +130,8 @@ void solve(const s_polynom *polynom, s_solution *solution)
{
if (is_nearly_equal_zero(power1))
{
// solve_degree_2_pure(&solution->solution_degree_2, power2, power0);
solution->is_quadratic_pure = true;
solve_degree_2_pure(&solution->solution_degree_2_pure, power2, power0);
}
else
solve_degree_2(&solution->solution_degree_2, power2, power1, power0);

View File

@@ -73,6 +73,7 @@ static void print_context_solution()
{
s_solution_degree_1 solution_d1;
s_solution_degree_2 solution_d2;
s_solution_degree_2_pure solution_d2_pure;
if (solution_g_err->degree == 1)
{
@@ -85,28 +86,51 @@ static void print_context_solution()
}
else if (solution_g_err->degree == 2)
{
solution_d2 = solution_g_err->solution_degree_2;
dprintf(STDERR_FILENO, "degree 2 : delta > 0 ( -b / 2a +- √Δ / 2a )\n");
dprintf(STDERR_FILENO, " delta == 0 ( -b / 2a )\n");
dprintf(STDERR_FILENO, " delta < 0 ( -b / 2a +- i√|Δ| / 2a )\n");
if (solution_g_err->is_quadratic_pure)
{
solution_d2_pure = solution_g_err->solution_degree_2_pure;
dprintf(STDERR_FILENO, "degree 2 pure : radicand > 0 ( +-( -c / 2a ) )\n");
dprintf(STDERR_FILENO, " radicand == 0 ( 0 )\n");
dprintf(STDERR_FILENO, " radicand < 0 ( +-i( -c / 2a ) )\n");
dprintf(STDERR_FILENO, "a : %15g ( a )\n", solution_d2.a);
dprintf(STDERR_FILENO, "b : %15g ( b )\n", solution_d2.b);
dprintf(STDERR_FILENO, "c : %15g ( c )\n", solution_d2.c);
dprintf(STDERR_FILENO, "a : %15g ( a )\n", solution_d2_pure.a);
dprintf(STDERR_FILENO, "c : %15g ( c )\n", solution_d2_pure.c);
dprintf(STDERR_FILENO, "delta : %15g ( Δ == b² - 4ac )\n", solution_d2.delta);
dprintf(STDERR_FILENO, "delta_sign : %15s ( '-' || '+' || '0' )\n", delta_sign_to_str(solution_d2.delta_sign));
dprintf(STDERR_FILENO, "delta_absolute : %15g ( |Δ| )\n", solution_d2.delta_absolute);
dprintf(STDERR_FILENO, "delta_sqrt : %15g ( √|Δ| )\n", solution_d2.delta_sqrt);
dprintf(STDERR_FILENO, "radicand : %15g ( r == x² == -c / a )\n", solution_d2_pure.radicand);
dprintf(STDERR_FILENO, "radicand_sign : %15s ( '-' || '+' || '0' )\n", radicand_sign_to_str(solution_d2_pure.radicand_sign));
dprintf(STDERR_FILENO, "radicand_absolute : %15g ( |r| )\n", solution_d2_pure.radicand_absolute);
dprintf(STDERR_FILENO, "radicand_sqrt : %15g ( √|r| )\n", solution_d2_pure.radicand_sqrt);
dprintf(STDERR_FILENO, "left_term : %15g ( -b / 2a )\n", solution_d2.left_term);
dprintf(STDERR_FILENO, "right_term : %15g ( √|Δ| / 2a )\n", solution_d2.right_term);
dprintf(STDERR_FILENO, "numerator_sqrt : %15g ( √a )\n", solution_d2_pure.numerator_sqrt);
dprintf(STDERR_FILENO, "numerator_sqrt_is_int : %15i ( false if √a is double )\n", solution_d2_pure.numerator_sqrt_is_int);
dprintf(STDERR_FILENO, "denominator_sqrt : %15g ( √c )\n", solution_d2_pure.denominator_sqrt);
dprintf(STDERR_FILENO, "denominator_sqrt_is_int: %15i ( false if √c is double )\n", solution_d2_pure.denominator_sqrt_is_int);
}
else
{
solution_d2 = solution_g_err->solution_degree_2;
dprintf(STDERR_FILENO, "degree 2 : delta > 0 ( -b / 2a +- √Δ / 2a )\n");
dprintf(STDERR_FILENO, " delta == 0 ( -b / 2a )\n");
dprintf(STDERR_FILENO, " delta < 0 ( -b / 2a +- i√|Δ| / 2a )\n");
dprintf(STDERR_FILENO, "all_int : %15i ( are int : b, a, √|Δ| )\n", solution_d2.all_int);
dprintf(STDERR_FILENO, "left_term_numerator : %15i ( -b / left_gcd )\n", solution_d2.left_term_numerator);
dprintf(STDERR_FILENO, "left_term_denominator : %15i ( 2a / left_gcd )\n", solution_d2.left_term_denominator);
dprintf(STDERR_FILENO, "right_term_numerator : %15i ( √|Δ| / right_gcd )\n", solution_d2.right_term_numerator);
dprintf(STDERR_FILENO, "right_term_denominator : %15i ( 2a / right_gcd )\n", solution_d2.right_term_denominator);
dprintf(STDERR_FILENO, "a : %15g ( a )\n", solution_d2.a);
dprintf(STDERR_FILENO, "b : %15g ( b )\n", solution_d2.b);
dprintf(STDERR_FILENO, "c : %15g ( c )\n", solution_d2.c);
dprintf(STDERR_FILENO, "delta : %15g ( Δ == b² - 4ac )\n", solution_d2.delta);
dprintf(STDERR_FILENO, "delta_sign : %15s ( '-' || '+' || '0' )\n", delta_sign_to_str(solution_d2.delta_sign));
dprintf(STDERR_FILENO, "delta_absolute : %15g ( |Δ| )\n", solution_d2.delta_absolute);
dprintf(STDERR_FILENO, "delta_sqrt : %15g ( √|Δ| )\n", solution_d2.delta_sqrt);
dprintf(STDERR_FILENO, "left_term : %15g ( -b / 2a )\n", solution_d2.left_term);
dprintf(STDERR_FILENO, "right_term : %15g ( √|Δ| / 2a )\n", solution_d2.right_term);
dprintf(STDERR_FILENO, "all_int : %15i ( are int : b, a, √|Δ| )\n", solution_d2.all_int);
dprintf(STDERR_FILENO, "left_term_numerator : %15i ( -b / left_gcd )\n", solution_d2.left_term_numerator);
dprintf(STDERR_FILENO, "left_term_denominator : %15i ( 2a / left_gcd )\n", solution_d2.left_term_denominator);
dprintf(STDERR_FILENO, "right_term_numerator : %15i ( √|Δ| / right_gcd )\n", solution_d2.right_term_numerator);
dprintf(STDERR_FILENO, "right_term_denominator : %15i ( 2a / right_gcd )\n", solution_d2.right_term_denominator);
}
}
ft_putchar_fd('\n', STDERR_FILENO);

View File

@@ -10,3 +10,48 @@ bool is_nearly_equal_zero(double num)
return false;
return true;
}
bool has_decimal_part(double num)
{
return (num != (int)num);
}
bool any_has_decimal_part(double *num, size_t len)
{
while (len > 0)
{
if (has_decimal_part(num[len - 1]))
return true;
len--;
}
return false;
}
// find GCD of two integers using euclidean algorithm
int gcd_int(int a, int b)
{
int tmp;
while (b != 0)
{
tmp = b;
b = a % b;
a = tmp;
}
return abs(a);
}
// returns the gcd, and modify arguments with new reduced values
int reduce_fraction(double *numerator, double *denominator)
{
int gcd;
if (any_has_decimal_part((double[]){*numerator, *denominator}, 2))
return 0;
gcd = gcd_int((int)*numerator, (int)*denominator);
*numerator /= gcd;
*denominator /= gcd;
return gcd;
}

View File

@@ -78,4 +78,16 @@ const char *delta_sign_to_str(e_delta_sign enum_value)
return "DELTA_ZERO";
else
return "invalid enum value";
}
const char *radicand_sign_to_str(e_radicand_sign enum_value)
{
if (enum_value == RADICAND_PLUS)
return "RADICAND_PLUS";
else if (enum_value == RADICAND_MINUS)
return "RADICAND_MINUS";
else if (enum_value == RADICAND_ZERO)
return "RADICAND_ZERO";
else
return "invalid enum value";
}

View File

@@ -324,3 +324,50 @@ Polynomial degree: 2
Discriminant is strictly negative, the two complex solutions are:
4.89898i/6
-4.89898i/6"
run_test \
"26. degree 2 pure" \
"3 * x^2 + 5 * x^1 - 2 * x^0 = 5 * x" "\
Reduced form: -2 * x^0 + 0 * x^1 + 3 * x^2 = 0
Polynomial degree: 2
Discriminant is strictly positive, the two solutions are:
√(2/3)
-√(2/3)"
run_test \
"27. degree 2 pure" \
"9 * x^2 + 5 * x^1 - 2 * x^0 = 5 * x" "\
Reduced form: -2 * x^0 + 0 * x^1 + 9 * x^2 = 0
Polynomial degree: 2
Discriminant is strictly positive, the two solutions are:
(√2)/3
-(√2)/3"
run_test \
"28. degree 2 pure" \
"3 * x^2 + 5 * x^1 - 4 * x^0 = 5 * x" "\
Reduced form: -4 * x^0 + 0 * x^1 + 3 * x^2 = 0
Polynomial degree: 2
Discriminant is strictly positive, the two solutions are:
2/√(3)
-2/√(3)"
run_test \
"29. degree 2 pure" \
"16 * x^2 + 5 * x^1 - 4 * x^0 = 5 * x" "\
Reduced form: -4 * x^0 + 0 * x^1 + 3 * x^2 = 0
Polynomial degree: 2
Discriminant is strictly positive, the two solutions are:
1/2
-1/2"
run_test \
"30. degree 2 pure" \
"4 * x^2 + 5 * x^1 - 16 * x^0 = 5 * x" "\
Reduced form: -4 * x^0 + 0 * x^1 + 3 * x^2 = 0
Polynomial degree: 2
Discriminant is strictly positive, the two solutions are:
2
-2"