Here is a somewhat longer function that handles the various cases for a quadratic equation of the form a*X^2 + b*X + c = 0 (only for real solutions!)

You will get None if no solution exists, Some [] if every X solves the equation (can only haben if a=b=c=0) or "Some" array with all the solutions (if you can write the equation in the form q(X-s)(X-s) = 0 then you will get Some [s; s] !)

let solveEq a b c =

if a = 0.0 && b = 0.0 && c = 0.0 then Some []

else if a = 0.0 && b = 0.0 && c <> 0.0 then None

else if a = 0.0 && b <> 0.0 then Some [ -c / b ]

else

let r = b*b - 4.0*a*c

if r < 0.0 then None

else

let r = System.Math.Sqrt(r)/(2.0*a)

let b = -b / (2.0*a)

Some [ b - r; b + r]

By on 1/19/2009 9:42 PM ()

CKoenig's solution seems to miss a minus before the b's in the regular case.

Anyway: here's a solution offering a choice between complex and real arguments and solutions. I used NaN to signal the 'everything is a solution' case.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#light

#r "FSharp.PowerPack.dll"

open System

open Microsoft.FSharp.Math

type Quadratic =

  static member Solve a b c =

    match Complex.magnitude a, Complex.magnitude b, Complex.magnitude c with

    | 0., 0., 0. -> [ complex Double.NaN 0. ]

    | 0., 0., _ -> []

    | 0., _, _ -> [ -c/b ]

    | _ ->

      let b,c = b/a, c/a

      let d = b*b - 4.*c |> sqrt

      [ -b+d ; -b-d ]

  [<OverloadID("Solve_float")>]

  static member Solve a b c =

    Quadratic.Solve (complex a 0.) (complex b 0.) (complex c 0.)

  static member SolveReal (a:float) b c =

    Quadratic.Solve a b c

    |> List.choose (fun c -> if c.ImaginaryPart = 0. then Some c.RealPart else None)

I guess you get what's meant by < and >. If I put in the actual signs the attribute seems an empty list...

By on 1/21/2009 7:21 AM ()

That's right - missed this minus - sorry.

BTW: I didn't figure out how to insert sourcecode in a reader-friendly way in here - can explain how you do this? Thanks. ... OK i spotted the "<code lang=fsharp>" Tags in there but do you have to insert in HTML-Mode? Maybe a Button on the Editor might be good for this forum ;)

By on 1/21/2009 9:39 PM ()

Well, I missed something too: dividing by 2. Here's a correct implementation (used FsCheck to validate this time...)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#light

#r "FSharp.PowerPack.dll"

open System

open Microsoft.FSharp.Math

let (|ComplexZero|) (c:complex) = c = Complex.Zero

let (|ComplexNaN|) (c:complex) = Double.IsNaN c.Magnitude

type Quadratic =

  static member Solve a b c =

    match a, b, c with

    | ComplexNaN true, _, _

    | _, ComplexNaN true, _

    | _, _, ComplexNaN true -> []

    | ComplexZero true, ComplexZero true, ComplexZero true -> [ complex Double.NaN 0. ]

    | ComplexZero true, ComplexZero true, _ -> []

    | ComplexZero true, _, _ -> [ -c/b ]

    | _ -> let d = b*b - 4.*a*c |> sqrt

           List.map ((*) ((complex 0.5 0.)/a)) [ -b+d ; -b-d ]

  [<OverloadID("Solve_float")>]

  static member Solve a b c =

    Quadratic.Solve (complex a 0.) (complex b 0.) (complex c 0.)

  static member SolveReal (a:float) b c =

    Quadratic.Solve a b c

    |> List.choose (fun c -> if c.ImaginaryPart = 0. then Some c.RealPart else None)

BTW: I use both the code bbcode (for highlighting) and a pre HTML-tag (for indenting). This seems to work OK

By on 1/21/2009 11:46 PM ()

Hi and thanks.

An interesting progression to very cleaver.

I've an error with the bracketed OverloadID in VS2008.
I've highlighted the angle brackets the documentation seems to indicate, but alas still error.
And I'm not finding the documentation on a single & ...?

Also I'm interested in hearing how you used FsCheck.

| _ -> let d = b*b - 4.*a*c |> sqrt

List.map ((*) ((complex 0.5 0.)/a)) [ -b+d ; -b-d ]

[<<OverloadID("Solve_float")>>]

static member Solve a b c =

Quadratic.Solve (complex a 0.) (complex b 0.) (complex c 0.)

static member SolveReal (a:float) b c =

By on 1/27/2009 10:53 AM ()

By "calculate", I assume you mean "solve".

Here is a start:

1
2
3
4
5
6
7
8
//ax**2 + b*x + c
let a = 1.0
let b = 5.0
let c = 6.0

//two roots
let x1 = (-b - sqrt(b**2.0 - 4.0*a*c))/2.0*a
let x2 = (-b + sqrt(b**2.0 - 4.0*a*c))/2.0*a
By on 1/7/2009 5:57 AM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper