views:

600

answers:

3

Hi,

I have to write a program to solve quadratics, returning a complex number result.

I've gotten so far, with defining a complex number, declaring it to be part of num, so +,- and * - ing can take place.

I've also defined a data type for a quadratic equation, but im now stuck with the actual solving of the quadratic. My math is quite poor, so any help would be greatly appreciated...

data Complex = C {
re :: Float,
im :: Float
} deriving Eq

-- Display complex numbers in the normal way

instance Show Complex where
    show (C r i)
     | i == 0   = show r
     | r == 0   = show i++"i"
     | r < 0 && i < 0 = show r ++ " - "++ show (C 0 (i*(-1)))
     | r < 0 && i > 0 = show r ++ " + "++ show (C 0 i)
     | r > 0 && i < 0 = show r ++ " - "++ show (C 0 (i*(-1)))
     | r > 0 && i > 0 = show r ++ " + "++ show (C 0 i)


-- Define algebraic operations on complex numbers
instance Num Complex where
    fromInteger n  = C (fromInteger n) 0 -- tech reasons
    (C a b) + (C x y) = C (a+x) (b+y)
    (C a b) * (C x y) = C (a*x - b*y) (b*x + b*y)
    negate (C a b)  = C (-a) (-b)

instance Fractional Complex where
    fromRational r  = C (fromRational r) 0 -- tech reasons
    recip (C a b)  = C (a/((a^2)+(b^2))) (b/((a^2)+(b^2)))


root :: Complex -> Complex
root (C x y)
    | y == 0 && x == 0 = C 0 0
    | y == 0 && x > 0 = C (sqrt ( ( x + sqrt ( (x^2) + 0 ) ) / 2 ) )  0
    | otherwise   = C (sqrt ( ( x + sqrt ( (x^2) + (y^2) ) ) / 2 ) ) ((y/(2*(sqrt ( ( x + sqrt ( (x^2) + (y^2) ) ) / 2 ) ) ) ) )


-- quadratic polynomial : a.x^2 + b.x + c
data Quad = Q {
    aCoeff, bCoeff, cCoeff :: Complex
    } deriving Eq


instance Show Quad where
    show (Q a b c) = show a ++ "x^2 + " ++ show b ++ "x + " ++ show c

solve :: Quad -> (Complex, Complex)
solve (Q a b c) = STUCK!

EDIT: I seem to have missed out the whole point of using my own complex number datatype is to learn about custom datatypes. I'm well aware that i could use complex.data. Any help that could be given using my solution so far would be greatly appreciated.\

EDIT 2: It seems that my initial question was worded horribly. I'm aware that the quadratic formula will return both (or just the one) root to me. Where I am having trouble is returning these roots as a (complex, complex) tuple with the code above.

I'm well aware that I could use the built in quadratic functions as have been displayed below, but this is not the exercise. The idea behind the exercise, and creating ones own complex number data type, is to learn about custom data types.

+5  A: 

Like newacct said, it's just the quadratic equation:

(-b +- sqrt(b^2 - 4ac)) / 2a
module QuadraticSolver where

import Data.Complex
data Quadratic a = Quadratic a a a deriving (Show, Eq)

roots :: (RealFloat a) => Quadratic a -> [ Complex a ]
roots (Quadratic a b c) = 
  if discriminant == 0 
  then [ numer / denom ]
  else [ (numer + root_discriminant) / denom,
         (numer - root_discriminant) / denom ]
  where discriminant = (b*b - 4*a*c)
        root_discriminant = if (discriminant < 0) 
                            then 0 :+ (sqrt $ -discriminant)
                            else (sqrt discriminant) :+ 0
        denom = 2*a :+ 0
        numer = (negate b) :+ 0

in practice:

ghci> :l QuadraticSolver
Ok, modules loaded: QuadraticSolver.
ghci> roots (Quadratic 1 2 1)
[(-1.0) :+ 0.0]
ghci> roots (Quadratic 1 0 1)
[0.0 :+ 1.0,(-0.0) :+ (-1.0)]

And adapting to use your terms:

solve :: Quad -> (Complex, Complex)
solve (Q a b c) = ( sol (+), sol (-) )
  where sol op = (op (negate b) $ root $ b*b - 4*a*c) / (2 * a)

Although I haven't tested that code

rampion
It works when there are real roots, thanks. "solve (Q 1 2 1)" produces "(-1.0,-1.0)" and "solve (Q 1 2 0)" produces "(0.0,-2.0)".Doens't solve non-real roots though. I will post a separate question on this though. "solve (Q 1 2 2)" causes this error ( Program error: pattern match failure: v1618_v1655 (C -1.#IND -1.#IND)
Thomas
+3  A: 

Since Haskell's sqrt can also handle complex numbers, rampion's solution can even be further simplified:

import Data.Complex

-- roots for quadratic equations with complex coefficients
croots :: (RealFloat a) =>
          (Complex a) -> (Complex a) -> (Complex a) -> [Complex a]
croots a b c
      | disc == 0 = [solution (+)]
      | otherwise = [solution (+), solution (-)]
   where disc = b*b - 4*a*c
         solution plmi = plmi (-b) (sqrt disc) / (2*a)

-- roots for quadratic equations with real coefficients
roots :: (RealFloat a) => a -> a -> a -> [Complex a]
roots a b c = croots (a :+ 0) (b :+ 0) (c :+ 0)

You can also use this croots function with your own datatype, if you change the types to fit your implementation (and call your root function instead of sqrt).

sth
rampion