add gcd if all int

This commit is contained in:
hugogogo
2026-05-14 12:31:32 +02:00
parent d770d7fc87
commit bbe0d65b1f
7 changed files with 120 additions and 95 deletions

View File

@@ -68,9 +68,6 @@ else
RM_OBJS = rm -rf $(D_OBJS)
endif
# EXECUTION FLAGS
RUN_FLAGS = -b
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
# . target: prerequisites . $@ : target #
@@ -106,7 +103,7 @@ $(NAME): $(OBJS)
run: $(NAME)
@echo $(B_PURPLE)"\n---------------------------------------------\n1. degree 2 \n"$(RESET)
-./$(NAME) $(RUN_FLAGS) "3 * x^2 + 5 * x^1 - 2 * x^0 = 5 * x^1"
-./$(NAME) -b -d "3x² + 5x - 2 = 5x"
test: $(NAME)
bash tester.sh

View File

@@ -2,7 +2,6 @@
## todo
- create tester
- if no "=" sign return error
- doing gcd for int values, and not for double values
- double is nearly_equal_0
@@ -20,63 +19,6 @@ this project uses submodules (maybe recursively), so either :
- `git clone --recurse-submodules <repo-url>`
- or, after cloning : `git submodule update --init --recursive`
## steps
1. lexer
-> tokens types :
- TOKEN_VARIABLE // x, y, etc.
- TOKEN_NUMBER_INT // int
- TOKEN_NUMBER_DOUBLE // double
- TOKEN_POWER // ^ or **
- TOKEN_SIGN_PLUS // +
- TOKEN_SIGN_MINUS // -
- TOKEN_FACTOR_MULT // *
- TOKEN_FACTOR_DIV // / or :
- TOKEN_EQUAL // =
- END // null
2. parser
-> terms :
- POSITION // left or righ from =
- SIGN // + or -
- COEFFICIENT // double
- EXPONENT // double
3. reduce
-> polynom :
- sign
- coefficient
- exponent
4. print reduced form
-> print reduced form
-> if degree 1 :
- if c = 0 -> print "any real is a solution"
- if c != 0 -> print "no solution"
-> if degree 2 :
- print degree
-> if degree 3 :
- print degree
5. solve
-> degree 1 :
-> ax + b = 0 <=> ax = -b <=> x = -b / a
-> solution :
- a; // double
- b; // double
- solution_gcd; // gcd(b, a)
- solution_numerator; // -b / gcd
- solution_denominator; // a / gcd
- solution; // double (-b / a)
-> degree 2 :
-> discriminant : Δ = b² - 4ac
-> Δ > 0 -> 2 solutions : x = ( -b / 2a ) +- ( √|Δ| / 2a )
-> Δ == 0 -> 1 solution : x = ( -b / 2a )
-> Δ < 0 -> 2 solutions : x = ( -b / 2a ) +- i( √|Δ| / 2a )
-> solution :
- delta_sign; // + or -
- delta; // Δ
- delta_absolute; // |Δ|
- delta_sqrt; // √|Δ|
- first_term; // double (-b / 2a)
- second_term; // double (√|Δ| / 2a)
6. print solution
---

View File

@@ -136,8 +136,13 @@ typedef struct
double delta; // Δ == b² - 4ac
double delta_absolute; // |Δ|
double delta_sqrt; // √|Δ|
double first_term; // double (-b / 2a)
double second_term; // double (√|Δ| / 2a)
double left_term; // double (-b / 2a)
double right_term; // double (√|Δ| / 2a)
bool all_int; // false if any is double : b, a, √|Δ|
int left_term_numerator; // -b / gcd
int left_term_denominator; // 2a / gcd
int right_term_numerator; // √|Δ| / gcd
int right_term_denominator; // 2a / gcd
} s_solution_degree_2;
typedef struct

View File

@@ -11,31 +11,49 @@ static void print_solution_degree_1(s_solution_degree_1 solution)
static void print_solution_delta_zero(s_solution_degree_2 solution)
{
ft_printf("Discriminant is equal to zero, the solution is:\n");
printf("%g\n", solution.first_term);
printf("%g\n", solution.left_term);
}
static void print_solution_delta_positiv(s_solution_degree_2 solution)
{
ft_printf("Discriminant is strictly positive, the two solutions are:\n");
printf("%g\n", solution.first_term + solution.second_term);
printf("%g\n", solution.first_term - solution.second_term);
printf("%g\n", solution.left_term + solution.right_term);
printf("%g\n", solution.left_term - solution.right_term);
}
static void print_solution_delta_negativ(s_solution_degree_2 solution)
{
ft_printf("Discriminant is strictly negative, the two complex solutions are:\n");
if (solution.all_int)
{
// solution 1
if (solution.b)
if (solution.b != 0.0)
printf("%g/%g + ", solution.b * -1, solution.a * 2);
printf("%gi/%g\n", solution.delta_sqrt, solution.a * 2);
// solution 2
if (solution.b)
if (solution.b != 0.0)
printf("%g/%g - ", solution.b * -1, solution.a * 2);
else
printf("-");
printf("%gi/%g\n", solution.delta_sqrt, solution.a * 2);
}
else
{
// solution 1
if (solution.left_term != 0.0)
printf("%g + ", solution.left_term);
if (solution.right_term != 0.0)
printf("i * %g\n", solution.right_term);
// solution 2
if (solution.left_term != 0.0)
printf("%g - ", solution.left_term);
else
printf("-");
printf("i * %g\n", solution.right_term);
}
}
void print_solution(s_solution *solution)
@@ -53,11 +71,11 @@ void print_solution(s_solution *solution)
{
solution_d2 = solution->solution_degree_2;
delta_sign = solution_d2.delta_sign;
if (delta_sign == 0)
if (delta_sign == DELTA_ZERO)
print_solution_delta_zero(solution_d2);
else if (delta_sign > 0)
else if (delta_sign == DELTA_PLUS)
print_solution_delta_positiv(solution_d2);
else if (delta_sign < 0)
else if (delta_sign == DELTA_MINUS)
print_solution_delta_negativ(solution_d2);
else
stop_errors("delta sign is wrong : '%i' , delta : '%g'", solution_d2.delta_sign, solution_d2.delta);

View File

@@ -32,6 +32,36 @@ static double positiv_zero(double num)
return num;
}
int has_decimal_part(double num)
{
return (num != (int)num);
}
int any_has_decimal_part(double *num, size_t len)
{
while (len > 0)
{
if (has_decimal_part(num[len - 1]))
return 1;
len--;
}
return 0;
}
// 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;
@@ -44,6 +74,7 @@ static void solve_degree_2(s_solution_degree_2 *solution, double a, double b, do
{
double delta;
double delta_sqrt;
int gcd;
solution->a = a;
solution->b = b;
@@ -56,11 +87,37 @@ static void solve_degree_2(s_solution_degree_2 *solution, double a, double b, do
solution->delta_sqrt = ft_sqrt(solution->delta_absolute); // √|Δ|
delta_sqrt = solution->delta_sqrt;
// terms
if (b)
solution->first_term = positiv_zero(-b / (2 * a)); // -b / 2a
if (delta)
solution->second_term = positiv_zero(delta_sqrt / 2 * a); // √|Δ| / 2a
/**
* SOLVE LEFT AND RIGHT TERMS AS DOUBLES
*/
if (b != 0.0)
solution->left_term = positiv_zero(-b / (2 * a)); // -b / 2a
if (delta != 0.0)
solution->right_term = positiv_zero(delta_sqrt / 2 * a); // √|Δ| / 2a
/**
* COMPLEX : SOLVE TERMS AS FRACTIONS
*/
// check
if (solution->delta_sign != DELTA_MINUS)
return;
if (any_has_decimal_part((double[]){b, a, solution->delta_sqrt}, 3))
return;
solution->all_int = true;
// right term
gcd = gcd_int((int)solution->delta_sqrt, (int)(a * 2));
solution->right_term_numerator = solution->delta_sqrt / gcd;
solution->right_term_denominator = (a * 2) / gcd;
// left term
if (b == 0.0)
return;
gcd = gcd_int((int)b, (int)(a * 2));
solution->left_term_numerator = -b / gcd;
solution->left_term_denominator = (a * 2) / gcd;
}
void solve(const s_polynom *polynom, s_solution *solution)

View File

@@ -99,8 +99,14 @@ static void print_context_solution()
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, "first_term : %15g ( -b / 2a )\n", solution_d2.first_term);
dprintf(STDERR_FILENO, "second_term : %15g ( √|Δ| / 2a )\n", solution_d2.second_term);
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

@@ -99,8 +99,8 @@ run_test \
Reduced form: 2 * x^0 + 0 * x^1 + 3 * x^2 = 0
Polynomial degree: 2
Discriminant is strictly negative, the two complex solutions are:
4.89898i/6
-4.89898i/6"
-√(2/3)
√(2/3)"
run_test \
"2. degree 2" \