From 37d9fa2f243c5439cee9e469e461a7f939021fbe Mon Sep 17 00:00:00 2001 From: hugogogo Date: Mon, 11 May 2026 22:36:55 +0200 Subject: [PATCH] complex solutions --- Makefile | 74 +++++++++++++++++----------------- README.md | 13 ++---- headers/computorv1.h | 40 +++++++------------ src/solver.c | 95 +++++--------------------------------------- src/utils/errors.c | 11 ----- src/utils/printer.c | 2 + 6 files changed, 65 insertions(+), 170 deletions(-) diff --git a/Makefile b/Makefile index 2c50b48..aac9fe8 100644 --- a/Makefile +++ b/Makefile @@ -67,7 +67,7 @@ else endif # EXECUTION FLAGS -RUN_FLAGS = -b +RUN_FLAGS = -b -d # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # @@ -103,48 +103,48 @@ $(NAME): $(OBJS) $(CC) $(OBJS) -o $@ $(LFLAGS) 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" +# @echo $(B_PURPLE)"\n---------------------------------------------\n1. degree 2 \n"$(RESET) +# -./$(NAME) $(RUN_FLAGS) "3 * x^2 + 5 * x^1 - 2 * x^0 = 5 * x^1" @echo $(B_PURPLE)"\n---------------------------------------------\n2. degree 2 \n"$(RESET) -./$(NAME) $(RUN_FLAGS) "3.4 * x^2 + 1 * x^1 - 2.0 * x^0 = 5 * x^1" - @echo $(B_PURPLE)"\n---------------------------------------------\n3. degree 2 \n"$(RESET) - -./$(NAME) $(RUN_FLAGS) "3 * x^2 + 2 * x^2 = 5 * x^1" - @echo $(B_PURPLE)"\n---------------------------------------------\n4. flag -e SHOULD FAIL \n"$(RESET) - -./$(NAME) $(RUN_FLAGS) -e "3 * x^2 + 2 * x - 7 * x^4 = 1 * x^4" - @echo $(B_PURPLE)"\n---------------------------------------------\n5. degree 2 \n"$(RESET) - -./$(NAME) $(RUN_FLAGS) "3*x^2 + 2x = 0" +# @echo $(B_PURPLE)"\n---------------------------------------------\n3. degree 2 \n"$(RESET) +# -./$(NAME) $(RUN_FLAGS) "3 * x^2 + 2 * x^2 = 5 * x^1" +# @echo $(B_PURPLE)"\n---------------------------------------------\n4. flag -e SHOULD FAIL \n"$(RESET) +# -./$(NAME) $(RUN_FLAGS) -e "3 * x^2 + 2 * x - 7 * x^4 = 1 * x^4" +# @echo $(B_PURPLE)"\n---------------------------------------------\n5. degree 2 \n"$(RESET) +# -./$(NAME) $(RUN_FLAGS) "3*x^2 + 2x = 0" @echo $(B_PURPLE)"\n---------------------------------------------\n6. degree 2 \n"$(RESET) -./$(NAME) $(RUN_FLAGS) "3.4 * x^2 + 1 * x^1 - 2.0 * x^0 = 5.123 * x^1" - @echo $(B_PURPLE)"\n---------------------------------------------\n7. float exponent SHOULD FAIL \n"$(RESET) - -./$(NAME) $(RUN_FLAGS) "3.4 * x^2 + 1 * x^1 - 2.0 * x^0 = 5 * x^1.2" - @echo $(B_PURPLE)"\n---------------------------------------------\n8. degree 4 \n"$(RESET) - -./$(NAME) $(RUN_FLAGS) "3x^2 + 2x -7x^4 = x^4" +# @echo $(B_PURPLE)"\n---------------------------------------------\n7. float exponent SHOULD FAIL \n"$(RESET) +# -./$(NAME) $(RUN_FLAGS) "3.4 * x^2 + 1 * x^1 - 2.0 * x^0 = 5 * x^1.2" +# @echo $(B_PURPLE)"\n---------------------------------------------\n8. degree 4 SHOULD FAIL \n"$(RESET) +# -./$(NAME) $(RUN_FLAGS) "3x^2 + 2x -7x^4 = x^4" @echo $(B_PURPLE)"\n---------------------------------------------\n9. degree 2 \n"$(RESET) -./$(NAME) $(RUN_FLAGS) "3x² + 2x -7x¹ = x" - @echo $(B_PURPLE)"\n---------------------------------------------\n10. degree 2 \n"$(RESET) - -./$(NAME) $(RUN_FLAGS) "3x² + 2x -7 = x" - @echo $(B_PURPLE)"\n---------------------------------------------\n11. degree 2 \n"$(RESET) - -./$(NAME) $(RUN_FLAGS) "-3x² + 2x -7 = x" - @echo $(B_PURPLE)"\n---------------------------------------------\n12. degree 2 \n"$(RESET) - -./$(NAME) $(RUN_FLAGS) "+3x² + 2x -7 = x" - @echo $(B_PURPLE)"\n---------------------------------------------\n13. degree 2 \n"$(RESET) - -./$(NAME) $(RUN_FLAGS) "3x² + 0x -7 = x" - @echo $(B_PURPLE)"\n---------------------------------------------\n14. degree 2 \n"$(RESET) - -./$(NAME) $(RUN_FLAGS) "3x² + 0x -0 = x" - @echo $(B_PURPLE)"\n---------------------------------------------\n15. degree 2 \n"$(RESET) - -./$(NAME) $(RUN_FLAGS) "3x² + 2x -0 = x" - @echo $(B_PURPLE)"\n---------------------------------------------\n16. degree 1 \n"$(RESET) - -./$(NAME) $(RUN_FLAGS) "3x + 2x -0 = x" - @echo $(B_PURPLE)"\n---------------------------------------------\n17. degree 2 \n"$(RESET) - -./$(NAME) $(RUN_FLAGS) "3x² + x -0 = x" - @echo $(B_PURPLE)"\n---------------------------------------------\n18. degree 2 \n"$(RESET) - -./$(NAME) $(RUN_FLAGS) "0x² + x -0 = x" - @echo $(B_PURPLE)"\n---------------------------------------------\n19. degree 5 SHOULD FAIL \n"$(RESET) - -./$(NAME) $(RUN_FLAGS) "2x⁵ + x -0 = -7x^5" - @echo $(B_PURPLE)"\n---------------------------------------------\n20. degree 1 \n"$(RESET) - -./$(NAME) $(RUN_FLAGS) "2x + x -0 = -7x" - @echo $(B_PURPLE)"\n---------------------------------------------\n20. degree 1 \n"$(RESET) - -./$(NAME) $(RUN_FLAGS) "2x + x -3 = -7x" +# @echo $(B_PURPLE)"\n---------------------------------------------\n10. degree 2 \n"$(RESET) +# -./$(NAME) $(RUN_FLAGS) "3x² + 2x -7 = x" +# @echo $(B_PURPLE)"\n---------------------------------------------\n11. degree 2 \n"$(RESET) +# -./$(NAME) $(RUN_FLAGS) "-3x² + 2x -7 = x" +# @echo $(B_PURPLE)"\n---------------------------------------------\n12. degree 2 \n"$(RESET) +# -./$(NAME) $(RUN_FLAGS) "+3x² + 2x -7 = x" +# @echo $(B_PURPLE)"\n---------------------------------------------\n13. degree 2 \n"$(RESET) +# -./$(NAME) $(RUN_FLAGS) "3x² + 0x -7 = x" +# @echo $(B_PURPLE)"\n---------------------------------------------\n14. degree 2 \n"$(RESET) +# -./$(NAME) $(RUN_FLAGS) "3x² + 0x -0 = x" +# @echo $(B_PURPLE)"\n---------------------------------------------\n15. degree 2 \n"$(RESET) +# -./$(NAME) $(RUN_FLAGS) "3x² + 2x -0 = x" +# @echo $(B_PURPLE)"\n---------------------------------------------\n16. degree 1 \n"$(RESET) +# -./$(NAME) $(RUN_FLAGS) "3x + 2x -0 = x" +# @echo $(B_PURPLE)"\n---------------------------------------------\n17. degree 2 \n"$(RESET) +# -./$(NAME) $(RUN_FLAGS) "3x² + x -0 = x" +# @echo $(B_PURPLE)"\n---------------------------------------------\n18. degree 2 SHOULD FAIL \n"$(RESET) +# -./$(NAME) $(RUN_FLAGS) "0x² + x -0 = x" +# @echo $(B_PURPLE)"\n---------------------------------------------\n19. degree 5 SHOULD FAIL \n"$(RESET) +# -./$(NAME) $(RUN_FLAGS) "2x⁵ + x -0 = -7x^5" +# @echo $(B_PURPLE)"\n---------------------------------------------\n20. degree 1 \n"$(RESET) +# -./$(NAME) $(RUN_FLAGS) "2x + x -0 = -7x" +# @echo $(B_PURPLE)"\n---------------------------------------------\n21. degree 1 \n"$(RESET) +# -./$(NAME) $(RUN_FLAGS) "2x + x -3 = -7x" clean: $(RM_OBJS) diff --git a/README.md b/README.md index ea89106..18af5af 100644 --- a/README.md +++ b/README.md @@ -64,21 +64,14 @@ this project uses submodules (maybe recursively), so either : -> Δ < 0 -> 2 solutions : x = ( -b / 2a ) +- i( √|Δ| / 2a ) -> solution : - delta_sign; // + or - + - delta; // Δ - delta_absolute; // |Δ| - delta_sqrt; // √|Δ| - - - first_term_gcd; // gcd(b, 2a) - - first_term_numerator; // -b / gcd - - first_term_denominator; // 2a / gcd - first_term; // double (-b / 2a) - - - second_term_gcd; // gcd(√|Δ|, 2a) - - second_term_numerator; // √|Δ| / gcd - - second_term_denominator; // 2a / gcd - second_term; // double (√|Δ| / 2a) - - double solution1; // first_term + second_term - - double solution2; // first_term - second_term + - double solution1; // first_term + second_term || -b / 2a + √|Δ| * i / 2a + - double solution2; // first_term - second_term || -b / 2a - √|Δ| * i / 2a 6. print solution --- diff --git a/headers/computorv1.h b/headers/computorv1.h index d504810..2e1b035 100644 --- a/headers/computorv1.h +++ b/headers/computorv1.h @@ -122,36 +122,24 @@ typedef enum typedef struct { - double a; // a in "ax + b" - double b; // b in "ax + b" - int solution_gcd; // gcd(b, a) - int solution_numerator; // -b / gcd - int solution_denominator; // a / gcd - double solution; // double (-b / a) + double a; // a in "ax + b" + double b; // b in "ax + b" + double solution; // double (-b / a) } s_solution_degree_1; 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 - double delta_absolute; // |Δ| - double delta_sqrt; // √|Δ| - // - int first_term_gcd; // gcd(b, 2a) - int first_term_numerator; // -b / gcd - int first_term_denominator; // 2a / gcd - double first_term; // double (-b / 2a) - // - int second_term_gcd; // gcd(√|Δ|, 2a) - int second_term_numerator; // √|Δ| / gcd - int second_term_denominator; // 2a / gcd - double second_term; // double (√|Δ| / 2a) - // - double solution1; // first_term + second_term - double solution2; // first_term - second_term (not if DELTA_ZERO) + 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 + double delta_absolute; // |Δ| + double delta_sqrt; // √|Δ| + double first_term; // double (-b / 2a) + double second_term; // double (√|Δ| / 2a) + double solution1; // || first_term + second_term || first_term + i * second_term + double solution2; // (not if DELTA_ZERO) || first_term - second_term || first_term - i * second_term } s_solution_degree_2; typedef struct diff --git a/src/solver.c b/src/solver.c index 665b890..9bf8c78 100644 --- a/src/solver.c +++ b/src/solver.c @@ -9,81 +9,12 @@ static double positiv_zero(double num) return num; } -static int count_decimal_places(double num) -{ - // handle negative numbers - num = ft_fabs(num); - - // isolate the fractional part - double int_part; - double frac_part = ft_modf(num, &int_part); - - // if there is no fractional part, return 0 - if (frac_part == 0.0) - { - return 0; - } - - // count the number of decimal places - int count = 0; - const int max_decimals = 15; // prevent infinite loops for irrational numbers - while (count < max_decimals) - { - double dummy_frac_part = ft_modf(frac_part, NULL); - if (dummy_frac_part == 0.0) - { - break; - } - frac_part *= 10; - count++; - } - - return count; -} - -// find GCD of two integers (Euclidean algorithm) -static int gcd_int(int a, int b) -{ - while (b != 0) - { - int temp = b; - b = a % b; - a = temp; - } - return a; -} - -// find GCD of two doubles -static int find_gcd(double numerator, double denominator) -{ - // count decimal places for both numbers (eg. 2.5 -> 1 , and 1.12345 -> 5) - int num_decimals = count_decimal_places(numerator); - int den_decimals = count_decimal_places(denominator); - - // use the maximum precision (eg. 5) - int max_decimals = ft_greater(num_decimals, den_decimals); - - // scale the numbers to integers (eg. 2.5*100000=250000 and 1.12345*100000=112345) - // using ft_round because floating-point multiplication can introduce tiny precision errors - // (e.g., 0.3 * 10 = 2.9999999999999996 instead of 3.0). - // rounding ensures these errors are corrected before converting to integers. - double scale = ft_pow(10, max_decimals); - int num_scaled = (int)ft_round(numerator * scale); - int den_scaled = (int)ft_round(denominator * scale); - - // compute GCD of the scaled integers - return gcd_int(abs(num_scaled), ft_abs(den_scaled)); -} - static void solve_degree_1(s_solution_degree_1 *solution, double a, double b) { solution->a = a; solution->b = b; - solution->solution_gcd = find_gcd(b, a); // gcd(b, a) - solution->solution_numerator = -b / solution->solution_gcd; // -b / gcd - solution->solution_denominator = a / solution->solution_gcd; // a / gcd - solution->solution = positiv_zero(-b / a); // -b / a + solution->solution = positiv_zero(-b / a); // -b / a } static void solve_degree_2(s_solution_degree_2 *solution, double a, double b, double c) @@ -102,17 +33,9 @@ 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; - // first term - solution->first_term_gcd = find_gcd(b, 2 * a); // gcd(b, 2a) - solution->first_term_numerator = -b / solution->first_term_gcd; // -b / gcd - solution->first_term_denominator = 2 * a / solution->first_term_gcd; // 2a / gcd - solution->first_term = positiv_zero(-b / (2 * a)); // -b / 2a - - // second term - solution->second_term_gcd = find_gcd(delta_sqrt, 2 * a); // gcd(√|Δ|, 2a) - solution->second_term_numerator = delta_sqrt / solution->second_term_gcd; // √|Δ| / gcd - solution->second_term_denominator = 2 * a / solution->second_term_gcd; // 2a / gcd - solution->second_term = positiv_zero(delta_sqrt / 2 * a); // √|Δ| / 2a + // terms + solution->first_term = positiv_zero(-b / (2 * a)); // -b / 2a + solution->second_term = positiv_zero(delta_sqrt / 2 * a); // √|Δ| / 2a // solution solution->solution1 = solution->first_term; // first_term + second_term @@ -121,12 +44,12 @@ static void solve_degree_2(s_solution_degree_2 *solution, double a, double b, do solution->solution1 = positiv_zero(solution->first_term); // -b / 2a solution->solution2 = NAN; // NAN (no solution) } - else if (solution->delta_sign == DELTA_MINUS) - { - solution->solution1 = positiv_zero(solution->first_term + solution->second_term); // -b / 2a + i√|Δ| / 2a - solution->solution2 = positiv_zero(solution->first_term - solution->second_term); // -b / 2a - i√|Δ| / 2a - } else if (solution->delta_sign == DELTA_PLUS) + { + solution->solution1 = positiv_zero(solution->first_term + solution->second_term); // -b / 2a + √Δ / 2a + solution->solution2 = positiv_zero(solution->first_term - solution->second_term); // -b / 2a - √Δ / 2a + } + else if (solution->delta_sign == DELTA_MINUS) { // no real solution, but can output irreal solution with 'i' solution->solution1 = NAN; diff --git a/src/utils/errors.c b/src/utils/errors.c index 88c026c..64ea62f 100644 --- a/src/utils/errors.c +++ b/src/utils/errors.c @@ -81,10 +81,6 @@ static void print_context_solution() dprintf(STDERR_FILENO, "a : %10g ( a )\n", solution_d1.a); dprintf(STDERR_FILENO, "b : %10g ( b )\n", solution_d1.b); - - dprintf(STDERR_FILENO, "gcd : %10i ( gcd( b, a ) )\n", solution_d1.solution_gcd); - dprintf(STDERR_FILENO, "numerator : %10i ( -b / gcd )\n", solution_d1.solution_numerator); - dprintf(STDERR_FILENO, "denominator : %10i ( a / gcd )\n", solution_d1.solution_denominator); dprintf(STDERR_FILENO, "solution : %10g ( -b / a )\n", solution_d1.solution); } else if (solution_g_err->degree == 2) @@ -103,14 +99,7 @@ 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_gcd : %15i ( gcd( b, 2a ) )\n", solution_d2.first_term_gcd); - dprintf(STDERR_FILENO, "first_term_numerator : %15i ( -b / gcd )\n", solution_d2.first_term_numerator); - dprintf(STDERR_FILENO, "first_term_denominator : %15i ( 2a / gcd )\n", solution_d2.first_term_denominator); dprintf(STDERR_FILENO, "first_term : %15g ( -b / 2a )\n", solution_d2.first_term); - - dprintf(STDERR_FILENO, "second_term_gcd : %15i ( gcd(√|Δ|, 2a ) )\n", solution_d2.second_term_gcd); - dprintf(STDERR_FILENO, "second_term_numerator : %15i ( √|Δ| / gcd )\n", solution_d2.second_term_numerator); - dprintf(STDERR_FILENO, "second_term_denominator: %15i ( 2a / gcd )\n", solution_d2.second_term_denominator); dprintf(STDERR_FILENO, "second_term : %15g ( √|Δ| / 2a )\n", solution_d2.second_term); dprintf(STDERR_FILENO, "solution1 : %15g ( (-b / 2a) + (√Δ / 2a) )\n", solution_d2.solution1); diff --git a/src/utils/printer.c b/src/utils/printer.c index 0093231..ccfd84d 100644 --- a/src/utils/printer.c +++ b/src/utils/printer.c @@ -191,6 +191,8 @@ void print_solution(s_solution *solution) else if (solution_d2.delta_sign < 0) { ft_printf("Discriminant is strictly negative, the two complex solutions are:\n"); + printf("%g/%g + %gi/%g\n", solution_d2.b * -1, solution_d2.a * 2, solution_d2.delta_absolute, solution_d2.a * 2); + printf("%g/%g - %gi/%g\n", solution_d2.b * -1, solution_d2.a * 2, solution_d2.delta_absolute, solution_d2.a * 2); } else {