You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
270 lines
10 KiB
OCaml
270 lines
10 KiB
OCaml
(* ************************************************************************** *)
|
|
(* *)
|
|
(* ::: :::::::: *)
|
|
(* main.ml :+: :+: :+: *)
|
|
(* +:+ +:+ +:+ *)
|
|
(* By: frdescam <marvin@42.fr> +#+ +:+ +#+ *)
|
|
(* +#+#+#+#+#+ +#+ *)
|
|
(* Created: 2022/11/27 23:10:10 by frdescam #+# #+# *)
|
|
(* Updated: 2023/03/10 17:10:37 by frdescam ### ########.fr *)
|
|
(* *)
|
|
(* ************************************************************************** *)
|
|
|
|
open Complex
|
|
open Types
|
|
|
|
let exit_error error_msg =
|
|
print_endline error_msg;
|
|
exit 1
|
|
|
|
let extract_data_from_argv () =
|
|
try
|
|
(
|
|
let polynomial_string = Sys.argv.(1) in
|
|
let lexbuf = Lexing.from_string polynomial_string in
|
|
Polynomial_parser.parse Polynomial_lexer.lex lexbuf
|
|
) with e -> exit_error "Syntax error"
|
|
|
|
let add_default_terms polynomial =
|
|
let reduced_form = polynomial.reduced_form
|
|
in
|
|
let degree = polynomial.degree
|
|
in
|
|
let reduced_form =
|
|
if not (List.exists (fun {exponent; _} -> exponent = 0) reduced_form)
|
|
then
|
|
{coefficient = 0.; exponent = 0} :: reduced_form
|
|
else
|
|
reduced_form
|
|
in
|
|
let reduced_form =
|
|
if degree > 0 && not (List.exists (fun {exponent; _} -> exponent = 1) reduced_form)
|
|
then
|
|
{coefficient = 0.; exponent = 1} :: reduced_form
|
|
else
|
|
reduced_form
|
|
in
|
|
let reduced_form =
|
|
if degree > 1 && not (List.exists (fun {exponent; _} -> exponent = 2) reduced_form)
|
|
then
|
|
{coefficient = 0.; exponent = 2} :: reduced_form
|
|
else
|
|
reduced_form
|
|
in
|
|
let reduced_form = List.sort (fun {exponent=e1; _} {exponent=e2; _} ->
|
|
compare e2 e1) reduced_form
|
|
in
|
|
{ polynomial with reduced_form = reduced_form }
|
|
|
|
let find_degree polynomial =
|
|
let degree = match polynomial.reduced_form with
|
|
| [] -> 0
|
|
| hd :: _ -> hd.exponent
|
|
in
|
|
{ polynomial with degree = degree }
|
|
|
|
let reduce_polynomial polynomial =
|
|
let all_terms = polynomial.left_terms @ List.map (fun {coefficient; exponent} ->
|
|
{
|
|
coefficient = -1. *. coefficient; exponent
|
|
}) polynomial.right_terms
|
|
in
|
|
let grouped_terms = List.fold_left (fun acc t ->
|
|
let exponent = t.exponent in
|
|
let (same, other) = List.partition (fun t' -> t'.exponent = exponent) acc in
|
|
let coefficient = List.fold_left
|
|
(fun acc {coefficient; _} -> acc +. coefficient)
|
|
0.
|
|
(t :: same)
|
|
in
|
|
(if coefficient = 0. then other else {coefficient; exponent} :: other))
|
|
[]
|
|
all_terms
|
|
in
|
|
let reduced_terms = List.sort (fun {exponent=e1; _} {exponent=e2; _} ->
|
|
compare e2 e1) grouped_terms
|
|
in
|
|
{ polynomial with reduced_form = reduced_terms }
|
|
|
|
let solve_0 polynomial =
|
|
let a = (List.nth polynomial.reduced_form 0).coefficient
|
|
in
|
|
{
|
|
polynomial with solution_1 =
|
|
Some (
|
|
match a with
|
|
| 0. -> AllReal
|
|
| _ -> NoSolutions
|
|
)
|
|
}
|
|
|
|
let solve_1 polynomial =
|
|
let a = (List.nth polynomial.reduced_form 0).coefficient
|
|
and b = (List.nth polynomial.reduced_form 1).coefficient
|
|
in
|
|
{
|
|
(* Solution = -b / a *)
|
|
polynomial with solution_1 =
|
|
Some (Solution (Complex.{
|
|
re = (-.b /. a);
|
|
im = 0.
|
|
}))
|
|
}
|
|
|
|
let compute_discriminant polynomial =
|
|
let a = (List.nth polynomial.reduced_form 0).coefficient
|
|
and b = (List.nth polynomial.reduced_form 1).coefficient
|
|
and c = (List.nth polynomial.reduced_form 2).coefficient
|
|
in
|
|
{
|
|
(* Discriminent = b² - 4ac *)
|
|
polynomial with discriminant =
|
|
Some (
|
|
b *. b -. 4. *. a *. c
|
|
)
|
|
}
|
|
|
|
let compute_solution_null_discriminant polynomial =
|
|
let a = (List.nth polynomial.reduced_form 0).coefficient
|
|
and b = (List.nth polynomial.reduced_form 1).coefficient
|
|
in
|
|
{
|
|
(* Solution = (-b / 2a *)
|
|
polynomial with solution_1 =
|
|
Some (Solution (Complex.{
|
|
re = (-.b /. (2. *. a));
|
|
im = 0.
|
|
}))
|
|
}
|
|
|
|
let compute_solutions_negative_discriminant polynomial =
|
|
let a = (List.nth polynomial.reduced_form 0).coefficient
|
|
and b = (List.nth polynomial.reduced_form 1).coefficient
|
|
and discriminant =
|
|
match polynomial.discriminant with
|
|
| Some d -> d;
|
|
| None -> exit_error "Internal error"
|
|
in
|
|
{
|
|
polynomial with
|
|
(* Solution 1 = (-b + i * sqrt(discriminant)) / 2a *)
|
|
solution_1 =
|
|
Some (Solution (Complex.{
|
|
re = (-.b /. (2. *. a));
|
|
im = ((Stdlib.sqrt (abs_float discriminant)) /. (2. *. a))
|
|
}));
|
|
(* Solution 1 = (-b - i * sqrt(discriminant)) / 2a *)
|
|
solution_2 =
|
|
Some (Solution (Complex.{
|
|
re = (-.b /. (2. *. a));
|
|
im = (-.(Stdlib.sqrt (abs_float discriminant)) /. (2. *. a))
|
|
}))
|
|
}
|
|
|
|
let compute_solutions_positive_discriminant polynomial =
|
|
let a = (List.nth polynomial.reduced_form 0).coefficient
|
|
and b = (List.nth polynomial.reduced_form 1).coefficient
|
|
and discriminant =
|
|
match polynomial.discriminant with
|
|
| Some d -> d;
|
|
| None -> exit_error "Internal error"
|
|
in
|
|
{
|
|
polynomial with
|
|
(* Solution 1 = (-b - sqrt(discriminant)) / 2a *)
|
|
solution_1 =
|
|
Some (Solution (Complex.{
|
|
re = ((-.b -. Stdlib.sqrt discriminant) /. (2. *. a));
|
|
im = 0.
|
|
}));
|
|
(* Solution 1 = (-b + sqrt(discriminant)) / 2a *)
|
|
solution_2 =
|
|
Some (Solution (Complex.{
|
|
re = ((-.b +. Stdlib.sqrt discriminant) /. (2. *. a));
|
|
im = 0.
|
|
}))
|
|
}
|
|
|
|
let solve_2 polynomial =
|
|
let polynomial = compute_discriminant polynomial
|
|
in
|
|
match polynomial.discriminant with
|
|
| Some d when d < 0. -> compute_solutions_negative_discriminant polynomial
|
|
| Some d when d > 0. -> compute_solutions_positive_discriminant polynomial
|
|
| _ -> compute_solution_null_discriminant polynomial
|
|
|
|
let print_solution solution =
|
|
let re = solution.re in
|
|
let im = solution.im in
|
|
if im = 0.
|
|
then Printf.printf "%f\n" re
|
|
else
|
|
let operator = if im > 0. then '+' else '-' in
|
|
let im = abs_float im in
|
|
Printf.printf "%f %c %fi\n" re operator im
|
|
|
|
let print_solutions polynomial =
|
|
match polynomial.solution_1 with
|
|
| Some NoSolutions -> print_endline "There is no solution to this polynomial."
|
|
| Some AllReal -> print_endline "All real numbers are solution of this polynomial."
|
|
| Some Solution s -> print_string "x1 : "; print_solution s
|
|
| None -> ();
|
|
;
|
|
match polynomial.solution_2 with
|
|
| Some Solution s -> print_string "x2 : "; print_solution s
|
|
| _ -> ()
|
|
|
|
let print_polynomial_term term =
|
|
if term.coefficient != 1. then
|
|
(
|
|
if term.coefficient >= 0. then
|
|
print_string "+ "
|
|
else
|
|
print_string "- ";
|
|
print_float (abs_float term.coefficient)
|
|
);
|
|
if term.exponent != 0 then
|
|
(
|
|
print_string "x";
|
|
if term.exponent != 1 then
|
|
(
|
|
print_string "^";
|
|
print_int term.exponent
|
|
)
|
|
);
|
|
print_string ""
|
|
|
|
let print_reduced_form polynomial =
|
|
print_string "Reduced form : ";
|
|
List.iter (fun t ->
|
|
print_polynomial_term t;
|
|
print_string " "
|
|
) polynomial.reduced_form;
|
|
print_string "\n"
|
|
|
|
let print_discriminant polynomial =
|
|
match polynomial.discriminant with
|
|
| Some d -> Printf.printf "Discriminant : %f\n" d
|
|
| None -> ()
|
|
|
|
let print_resolved_polynomial polynomial =
|
|
print_reduced_form polynomial;
|
|
print_discriminant polynomial;
|
|
print_solutions polynomial
|
|
|
|
let _ =
|
|
if Array.length Sys.argv != 2 then
|
|
exit_error "Error: invalid argument count";
|
|
|
|
let polynomial =
|
|
extract_data_from_argv () |> reduce_polynomial |> find_degree |> add_default_terms
|
|
in
|
|
let polynomial =
|
|
match polynomial.degree with
|
|
| 0 -> solve_0 polynomial
|
|
| 1 -> solve_1 polynomial
|
|
| 2 -> solve_2 polynomial
|
|
| _ -> exit_error "Error: polynomials after 2nd degree aren't supported"
|
|
in
|
|
print_resolved_polynomial polynomial
|