Haskell и квадратичные вычисления

Мне нужно написать программу для решения квадратичных уравнений, возвращающую результат в виде комплексного числа.

Я зашел так далеко, определив комплексное число, объявив его частью num, поэтому +,- и * - ing могут иметь место.

Я также определил тип данных для квадратного уравнения, но теперь я застрял на фактическом решении квадратного уравнения. Моя математика довольно плохая, поэтому любая помощь будет принята с благодарностью...

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!

РЕДАКТИРОВАТЬ: я, кажется, упустил весь смысл использования моего собственного типа данных комплексного числа, чтобы узнать о пользовательских типах данных. Я хорошо знаю, что могу использовать complex.data. Будем очень признательны за любую помощь, которая может быть оказана с использованием моего решения.\

EDIT 2: Кажется, мой первоначальный вопрос был сформулирован ужасно. Я знаю, что квадратичная формула вернет мне оба (или только один) корень. У меня возникают проблемы с возвратом этих корней в виде (сложного, сложного) кортежа с приведенным выше кодом.

Я хорошо знаю, что мог бы использовать встроенные квадратичные функции, как показано ниже, но это не упражнение. Идея упражнения и создания собственного типа данных комплексного числа состоит в том, чтобы узнать о пользовательских типах данных.


person Thomas    schedule 03.08.2009    source источник
comment
вы можете использовать Complex из Data.Complex   -  person yairchu    schedule 03.08.2009
comment
Я мог бы, но нам сказали определить наши собственные сложные типы данных. Бит, с которым у меня возникли проблемы, - это преобразование квадратичного многочлена в действительной форме: a.x^2 + b.x + c в комплексные числа.   -  person Thomas    schedule 03.08.2009
comment
это то же самое. у вас есть все необходимые операции, просто используйте ту же формулу. (-b +/- (sqrt (bb-4ac))/2a ...   -  person nlucaroni    schedule 03.08.2009
comment
хорошо, но как мне заставить его вернуться как (сложный, сложный) кортеж?   -  person Thomas    schedule 04.08.2009
comment
не надо. Вернуть список - так как может быть только уникальный корень.   -  person rampion    schedule 04.08.2009
comment
Хотя я ценю ваш ответ и, конечно же, согласен, что это лучший способ сделать это, я хотел бы попытаться решить его так, как начал. Именно так мне было поручено сделать это ради изучения типов данных. Может ли кто-нибудь помочь мне завершить это так, как я начал?   -  person Thomas    schedule 04.08.2009
comment
Какой у вас ваш вопрос? Корни ax²+bx+c=0 равны (-b ± √(b²-4ac))/(2a). Что еще нужно знать?   -  person ShreevatsaR    schedule 04.08.2009
comment
Привет, я знаю, что квадратичная формула возвращает корни. Мой вопрос, и изначально он был сформулирован плохо, как вернуть корни в виде (сложного, сложного) кортежа, используя приведенный выше код. (Я прекрасно понимаю, что может быть один и тот же корень).   -  person Thomas    schedule 04.08.2009


Ответы (2)


Как сказал newacct, это просто квадратное уравнение:

(-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

на практике:

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)]

И адаптируясь к вашим терминам:

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)

Хотя я не тестировал этот код

person rampion    schedule 03.08.2009
comment
Работает, когда есть настоящие корни, спасибо. решить (Q 1 2 1) дает (-1,0, -1,0) и решить (Q 1 2 0) дает (0,0, -2,0). Однако не решает ненастоящие корни. Я опубликую отдельный вопрос по этому поводу. решить (Q 1 2 2) вызывает эту ошибку (Ошибка программы: ошибка сопоставления шаблона: v1618_v1655 (C -1.#IND -1.#IND) - person Thomas; 04.08.2009

Поскольку sqrt в Haskell также может обрабатывать комплексные числа, решение Рэмпиона можно еще больше упростить:

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)

Вы также можете использовать эту функцию croots со своим собственным типом данных, если вы измените типы в соответствии с вашей реализацией (и вызовете функцию root вместо sqrt).

person sth    schedule 03.08.2009