3

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.

Thomas
  • 63
  • 1
  • 6
  • 3
    you can use `Complex` from `Data.Complex` – yairchu Aug 03 '09 at 19:35
  • I could, but we were told to define our own complex data types. The bit i'm having trouble with is converting the real form quadratic polynomial : a.x^2 + b.x + c into complex numbers. – Thomas Aug 03 '09 at 19:45
  • it's the same. you have all the operations necessary, just use the same formula. (-b +/- (sqrt (bb-4ac))/2a ... – nlucaroni Aug 03 '09 at 19:51
  • ok, but how do I go about getting it to return as a (complex, complex) tuple? – Thomas Aug 03 '09 at 20:04
  • don't. Return a list - since there may be only a unique root. – rampion Aug 03 '09 at 20:15
  • While I apreciate your answer, and certainly agree its the best way to do it, i'd like to try and solve it the way I have started it. It's how I've been tasked to do it, for the sake of learning datatypes. Is it possible for someone to help me complete this the way I have started it? – Thomas Aug 03 '09 at 20:41
  • What *is* your question? The roots of ax²+bx+c=0 are (-b ± √(b²-4ac))/(2a). What more do you need to know? – ShreevatsaR Aug 03 '09 at 22:14
  • Hi, I know that the quadratic formula returns the roots. My question is, and it has been initially worded badly, how to return the roots as a (complex, complex) tuple, using the above code. (I'm well aware there may be the same root). – Thomas Aug 04 '09 at 08:35

2 Answers2

6

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
  • 87,131
  • 49
  • 199
  • 315
  • 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 Aug 04 '09 at 10:01
5

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
  • 222,467
  • 53
  • 283
  • 367