defmodule Chi2fit.Roots do # Copyright 2015-2017 Pieter Rijken # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. @moduledoc """ Solves roots for linear, quadratic, and cubic equations. """ @doc """ Returns the real roots of polynoms of order 1, 2 and 3 as a list. ## Examples Solve `2.0*x + 5.0 = 0` iex> solve [2.0,5.0] [-2.5] iex> solve [2.0,-14.0,24.0] [4.0,3.0] iex> solve [1.0,0.0,5.0,6.0] [-0.9999999999999999] """ @spec solve([float]) :: [float] def solve([+0.0|rest]), do: solve rest def solve([a1,a0]), do: [-a0/a1] def solve([a2,a1,a0]) do sqr = a1*a1-4*a2*a0 cond do sqr == 0 -> -a1/2/a2 sqr > 0 -> [(-a1+:math.sqrt(sqr))/2/a2,(-a1-:math.sqrt(sqr))/2/a2] true -> [] end end def solve([1.0,+0.0,p,q]) do ## For details see equations (83) and (84) in http://mathworld.wolfram.com/CubicFormula.html c = -0.5*q*:math.pow(3/abs(p),1.5) cond do p>0 -> [:math.sinh(1.0/3.0*:math.asinh(c))] c>=1 -> [:math.cosh(1.0/3.0*:math.acosh(c))] c<=-1 -> [-:math.cosh(1.0/3.0*:math.acosh(abs(c)))] true -> ## Three real solutions [:math.cos(1.0/3.0*:math.acos(c)),:math.cos(1.0/3.0*:math.acos(c) + 2*:math.pi()/3.0),:math.cos(1.0/3.0*:math.acos(c) + 4*:math.pi()/3.0)] end |> Enum.map(&(&1*2*:math.sqrt(abs(p)/3.0))) end def solve([1.0,a2,a1,a0]), do: solve([1.0,0.0,(3*a1-a2*a2)/3.0,(2*a2*a2*a2-9*a1*a2+27*a0)/27.0]) |> Enum.map(&(&1-a2/3.0)) def solve([a3,a2,a1,a0]), do: solve([1.0,a2/a3,a1/a3,a0/a3]) end