let solve_deg_4 ?(imeps=0.000001) ?(compeps=0.00000000001) (t,a1,b1,c1,d1) =
!print_check
(Printf.sprintf "solving %fX^4 + %fX^3 + %fX^2 + %fX + %f = 0"
t a1 b1 c1 d1);
let a1 = a1 /. t
and b1 = b1 /. t
and c1 = c1 /. t
and d1 = d1 /. t in
let b = (-. 3. /. 8.) *. (a1 ** 2.0) +. b1
and c = ((a1 ** 3.0) /. 8.) -. (a1 *. b1 /. 2.) +. c1
and d = (-. 3. /. 256.) *. (a1 ** 4.0) +.
(b1 *. (a1 ** 2.0) /. 16.) -. (a1 *. c1 /. 4.) +. d1 in
let real_or_complex c =
if c.Complex.im >= -. imeps && c.Complex.im <= imeps then
`Real c.Complex.re
else
`Complex c
in
let to_sol = function
`Real z ->
let x = z -. a1 /. 4. in
!print_check
(Printf.sprintf "%f^4 + a1 %f^3 + b1 %f^2 + c1 %f + d1 = %f"
x x x x
((x**4.0) +. a1 *. (x**3.0) +. b1 *. (x**2.0) +. c1 *. x +. d1)
);
`Real x
| `Complex z ->
let c = { z with Complex.re = z.Complex.re -. a1 /. 4. } in
let s = string_of_complex c in
let sum =
List.fold_left
Complex.add
{Complex.re = d1; Complex.im = 0.0}
[ (c **? 4.0) ;
a1 *? (c **? 3.0);
b1 *? (c **? 2.0);
c1 *? c ;
]
in
!print_check (Printf.sprintf " %s^4 + b/a %s^3 + c/a %s^2 + d/a %s + e/a = %s"
s s s s (string_of_complex sum));
`Complex c
in
let to_sol = function
`Real x -> to_sol (`Real x)
| `Complex c -> to_sol (real_or_complex c)
in
if d >= -. compeps && d <= compeps then
let (z1,z2,z3) = solve_deg_3 (1.0, 0.0, b, c) in
(to_sol (`Real 0.0), to_sol z1, to_sol z2, to_sol z3)
else
if c >= -. compeps && c <= compeps then
let (z1,z2) = solve_deg_2 (1.0, b, d) in
let to_sol2 = function
`Real x -> to_sol (`Real (sqrt x))
| `Complex _ -> `Real nan
in
let to_sol2' = function
`Real x -> to_sol (`Real (-. (sqrt x)))
| `Complex _ -> `Real nan
in
(to_sol2 z1, to_sol2' z1, to_sol2 z2, to_sol2' z2)
else
begin
let (g1,g2,g3) =
match solve_deg_3 (1.0, 8. *. b, 16. *.((b**2.0) -. 4. *. d), -. (64.0 *. (c**2.0))) with
(`Real g1, `Real g2, `Real g3) ->
({ Complex.re = g1 ; im = 0.0 },
{ Complex.re = g2 ; im = 0.0 },
{ Complex.re = g3 ; im = 0.0 })
| (`Real g1, `Complex g2, `Complex g3) ->
({ Complex.re = g1 ; im = 0.0 }, g2, g3)
| _ -> assert false
in
let ro1 = Complex.sqrt g1 in
let ro2 = Complex.sqrt g2 in
let ro3 =
let r = { Complex.re = (-. 8.) *. c; im = 0.0 } in
prerr_endline (Printf.sprintf "-8c = %s" (string_of_complex r));
Complex.div r (Complex.mul ro1 ro2)
in
let g3' = ro3 **? 2.0 in
!print_check (Printf.sprintf "g3'=%s =? %s=g3"
(string_of_complex g3')
(string_of_complex g3)
);
let foo = Complex.mul ro1 (Complex.mul ro2 ro3) in
!print_check
(Printf.sprintf "ro1.ro2.ro3 = %s\n-8c = %f"
(string_of_complex foo)
(-. 8. *. c)
);
let (+?) = Complex.add and (-?) = Complex.sub in
let q = 1. /. 4. in
let x1 = to_sol (`Complex (q *? (ro1 +? ro2 +? ro3)))
and x2 = to_sol (`Complex (q *? ((ro1 -? ro2) -? ro3)))
and x3 = to_sol (`Complex (q *? ((ro2 -? ro3) -? ro1)))
and x4 = to_sol (`Complex (q *? ((ro3 -? ro1) -? ro2))) in
(x1, x2, x3, x4)
end