Haskell和二次方程式

3

我需要编写一个程序来解决二次方程,并返回复数结果。

我已经定义了一个复数,并将其声明为num的一部分,因此可以进行加、减和乘法。

我还为二次方程定义了一个数据类型,但是现在我卡在了实际解决二次方程上。我的数学很差,所以任何帮助都将不胜感激...

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。非常感谢能够利用 我的 解决方案给予任何帮助。

编辑 2: 我的初始问题似乎措辞不当。我知道二次公式会返回一个或两个根。我遇到困难的地方是,如何使用上述代码将这些根作为 (complex, complex) 元组返回。

我很清楚我可以使用下面展示的内置二次函数,但这并不是练习的目的。练习的目的,以及创建自己的复数数据类型,是为了学习自定义数据类型。


3
你可以使用 Data.Complex 中的 Complex - yairchu
我本来可以这么做,但我们被告知要定义自己的复杂数据类型。让我感到困惑的是将实数形式的二次多项式:a.x^2 + b.x + c 转换成复数的问题。 - Thomas
你已经拥有所有必要的操作,只需使用相同的公式即可。(-b +/- (sqrt(bb-4ac))/2a ... - nlucaroni
你有什么问题?ax²+bx+c=0的根为(-b ± √(b²-4ac))/(2a)。你还需要知道什么? - ShreevatsaR
嗨,我知道二次公式可以返回根。我的问题是,一开始表述得不好,如何使用上面的代码将根作为(复数,复数)元组返回。(我很清楚可能存在相同的根)。 - Thomas
显示剩余3条评论
2个回答

6

就像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)

虽然我没有测试过那段代码


当存在实根时,它是有效的,谢谢。"solve (Q 1 2 1)" 产生 "(-1.0,-1.0)" 和 "solve (Q 1 2 0)" 产生 "(0.0,-2.0)"。但不能解决非实根。我将单独发布一个问题。"solve (Q 1 2 2)" 导致此错误(程序错误:模式匹配失败:v1618_v1655(C -1.#IND -1.#IND))。 - Thomas

5

由于Haskell的sqrt函数还可以处理复数,因此rampion的解决方案甚至可以进一步简化:

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)

如果您更改类型以适应您的实现(并调用您的root函数而不是sqrt),则可以使用此croots函数来处理自己的数据类型。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接