Skip to content

Instantly share code, notes, and snippets.

@ericnormand
Last active July 15, 2020 19:48
Show Gist options
  • Save ericnormand/46a47b418aaa41604f8d226ee3e9ab09 to your computer and use it in GitHub Desktop.
Save ericnormand/46a47b418aaa41604f8d226ee3e9ab09 to your computer and use it in GitHub Desktop.

roots of a quadratic equation

Quadratic equations can be represented by three numbers, a, b, and c, which are the coefficient of x^2, the coefficient of x, and the constant term. The roots of a quadratic equation are everywhere where it touches the x axis, meaning the equation is equal to zero.

You can use the quadratic formula which calculates the roots. In fact, that's your task: write a function that returns the roots of a quadratic equation using the quadratic formula. Here is more information about it.

Note: you don't have to return complex roots if the curve does not cross the x-axis.

Thanks to this site for the challenge idea where it is considered Medium level in Python.

Email submissions to eric@purelyfunctional.tv before July 12, 2020. You can discuss the submissions in the comments below.

(defn quadratic-roots [[a b c]]
(let [m (* -1/2 (/ b a))
d (Math/sqrt (- (* m m) (/ c a)))]
[(+ m d) (- m d)]))
(defn roots [[a b c]]
(let [discr (- (* b b) (* 4 a c))]
(if (neg? discr)
#{}
(let [sd (/ (Math/sqrt discr) 2 a)
bpart (/ (- b) 2 a)]
(conj #{}
(+ bpart sd)
(- bpart sd))))))
;; per Po-Shen Loh - https://www.poshenloh.com/quadraticdetail/
;; ax^2 +bx +c
;; divide off a to make polynomial monic
;; then roots are b/2a + u and b/2a - u
;; b/2a^2 - u^2 = c/a
;; therefore u = sqrt(b/2a^2 - c/a)
(defn qsolv [a b c]
(let [hb (/ b a -2)
u (Math/sqrt (- (* hb hb) (/ c a)))]
(distinct [(+ hb u) (- hb u)])))
;; some tests
[(= [-1.5857864376269049 -4.414213562373095]
(qsolv 1 6 7))
(= [-0.19999999999999996 -1.0]
(qsolv 5 6 1))
(= [1.0 -3.0]
(qsolv 1 2 -3))
(= [3.0 0.5]
(qsolv 2 -7 3))
(= [13.348469228349535 -1.3484692283495345]
(qsolv 1 -12 -18))
(= [2.0]
(qsolv 1 -4 4))
(= [0.0]
(qsolv 1 0 0))
(= [4.0 3.0]
(qsolv 1 -7 12))]
(defn quadratic-equation [a b c]
(let [discriminant (- (* b b) (* 4 a c))]
(when-not (neg? discriminant)
(distinct (map #(/ (% (- b) (Math/sqrt discriminant))
2 a)
[+ -])))))
(defn quad [a b c]
(let [disc (- (* b b) (* 4 a c))]
(when (and (>= disc 0) (not= a 0))
(let [w (Math/sqrt disc)]
(set (map #(/ (- % b) (* 2 a)) [w (- w)]))))))
(ns th.scratch.quadratic-formula)
(defn real-solutions [a b c]
(let [discriminant (- (* b b)
(* 4 a c))]
(cond
(pos? discriminant) [(/ (+ (- b) discriminant)
(* 2 a))
(/ (- (- b) discriminant)
(* 2 a))]
(zero? discriminant) [(/ (- b)
(* 2 a))]
(neg? discriminant) [])))
(comment
(for [[a b c] [[1 -4 3] [4 -8 3] [1 4 4] [1 2 4]]]
(real-solutions a b c))
;; => ([4 0] [3 -1] [-2] [])
)
(defn ^:dynamic *make-complex* [re im]
{:re re
:im im})
(defn real->complex [r]
(*make-complex* r 0))
(defn complex-solutions [a b c]
(let [discriminant (- (* b b)
(* 4 a c))]
(cond
(pos? discriminant)
(map real->complex
[(/ (+ (- b) discriminant)
(* 2 a))
(/ (- (- b) discriminant)
(* 2 a))])
(zero? discriminant)
(map real->complex
[(/ (- b)
(* 2 a))
(/ (- b)
(* 2 a))])
(neg? discriminant)
[(*make-complex* (/ (- b)
(* 2 a))
(/ (Math/sqrt (- discriminant))
(* 2 a)))
(*make-complex* (/ (- b)
(* 2 a))
(- (/ (Math/sqrt (- discriminant))
(* 2 a))))])))
(comment
(for [[a b c] [[1 -4 3] [4 -8 3] [1 4 4] [1 2 4]]]
(complex-solutions a b c))
;; => (({:re 4, :im 0} {:re 0, :im 0})
;; ({:re 3, :im 0} {:re -1, :im 0})
;; ({:re -2, :im 0} {:re -2, :im 0})
;; [{:re -1, :im 1.7320508075688772} {:re -1, :im -1.7320508075688772}])
)
@bobbicodes
Copy link

Much appreciate the Po-Shen Loh solution! I learned it from Grant Sanderson who explains it very well in this 3blue1brown video: https://www.youtube.com/watch?v=MHXO86wKeDY&t=2076s

Regarding the different approaches to the classic formula that Eric wrote about in the follow-up, I think that each refactoring is important and should be used to expand our understanding because it illuminates the problem space from another angle. I want to try to find even more ways to do it!

@bobbicodes
Copy link

Inspired by this (as well as Eric's markdown editor), I built a little reagent app for rendering LaTeX formulas from vector representations of polynomial coefficients (eg. [2 7 6) -> "2x^2 + 7x + 6"):

https://github.com/porkostomus/mecca-math

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment