<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Ravi Numerics]]></title><description><![CDATA[Ravi Numerics]]></description><link>https://ravi-numerics.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Sun, 15 Nov 2026 18:35:18 GMT</lastBuildDate><atom:link href="https://ravi-numerics.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[A Numerically Stable Quadratic Solver in Python (with Steps)]]></title><description><![CDATA[Most "quadratic formula" snippets online stop at two lines of code. That is fine until you hit a negative discriminant, a = 0, or floating-point noise that…]]></description><link>https://ravi-numerics.hashnode.dev/a-numerically-stable-quadratic-solver-in-python-with-steps</link><guid isPermaLink="true">https://ravi-numerics.hashnode.dev/a-numerically-stable-quadratic-solver-in-python-with-steps</guid><category><![CDATA[Python]]></category><category><![CDATA[algorithms]]></category><category><![CDATA[Math]]></category><dc:creator><![CDATA[Ravi Patel]]></dc:creator><pubDate>Tue, 10 Nov 2026 10:46:24 GMT</pubDate><content:encoded><![CDATA[<p>Most "quadratic formula" snippets online stop at two lines of code. That is fine until you hit a negative discriminant, a = 0, or floating-point noise that turns a double root into two slightly different numbers. Here is a small, careful solver in Python that handles all of those cases and prints each step, which is handy when you are building study tools or checking homework.</p>
<h2>The math in one paragraph</h2>
<p>For ax² + bx + c = 0 with a ≠ 0, the discriminant D = b² − 4ac decides everything. D &gt; 0 gives two real roots, D = 0 gives one repeated root, and D &lt; 0 gives a pair of complex conjugate roots. The roots are x = (−b ± √D) / 2a.</p>
<h2>A step-by-step solver</h2>
<pre><code class="language-python">import cmath
import math

def solve_quadratic(a: float, b: float, c: float, eps: float = 1e-12):
    steps = []
    if abs(a) &lt; eps:
        if abs(b) &lt; eps:
            return steps + ["a = 0 and b = 0: not an equation in x"], []
        x = -c / b
        return steps + [f"a = 0, so it is linear: x = -c/b = {x:g}"], [x]

    D = b * b - 4 * a * c
    steps.append(f"Discriminant D = b^2 - 4ac = {b:g}^2 - 4({a:g})({c:g}) = {D:g}")

    if abs(D) &lt; eps:
        x = -b / (2 * a)
        steps.append(f"D = 0, one repeated root: x = -b/2a = {x:g}")
        return steps, [x]

    if D &gt; 0:
        # Numerically stable form: avoid subtracting nearly equal numbers
        q = -0.5 * (b + math.copysign(math.sqrt(D), b))
        x1, x2 = q / a, c / q
        steps.append(f"D &gt; 0, two real roots: x1 = {x1:g}, x2 = {x2:g}")
        return steps, sorted([x1, x2])

    r = cmath.sqrt(D)
    x1, x2 = (-b + r) / (2 * a), (-b - r) / (2 * a)
    steps.append(f"D &lt; 0, complex roots: {x1:.4g} and {x2:.4g}")
    return steps, [x1, x2]

for coeffs in [(2, -7, 3), (1, -6, 9), (1, 2, 5), (0, 4, -8), (1, 1e8, 1)]:
    steps, roots = solve_quadratic(*coeffs)
    print(coeffs, "-&gt;", roots)
    for s in steps:
        print("   ", s)
</code></pre>
<h2>Why the "stable" branch matters</h2>
<p>Try a = 1, b = 10⁸, c = 1. The textbook formula computes (−b + √D) by subtracting two numbers that agree in almost every digit, and you lose most of your precision. The small root comes out as 0 or as garbage. Computing q = −½(b + sign(b)·√D) first and then using x₁ = q/a and x₂ = c/q (Vieta's formula, x₁·x₂ = c/a) keeps full precision for both roots.</p>
<h2>Testing it</h2>
<p>Check each root by plugging it back in: a·x² + b·x + c should be close to 0. For 2x² − 7x + 3 you should get x = 0.5 and x = 3. For x² − 6x + 9 you should get the single root 3. For x² + 2x + 5 you should get −1 ± 2i.</p>
<h2>Checking your work</h2>
<p>When you're studying by hand, it helps to compare each line of your working against a worked solution. I use the free step-by-step <a href="https://mathssolvergpt.com/en">MathGPT AI math solver</a> for that, alongside small scripts like this one.</p>
<h2>Takeaways</h2>
<ul>
<li>Handle a = 0 separately, because it's a linear equation.</li>
<li>Use a tolerance for D = 0 instead of an exact comparison.</li>
<li>Use the stable form for real roots when |b| is large.</li>
<li>Use cmath for negative discriminants instead of raising an error.</li>
</ul>
]]></content:encoded></item></channel></rss>