Section 1.8 Example 2: Quadratic Equation#

Adapted from: “Guide to Fortran 2008 Programming” by Walter S. Brainerd (Springer 2015)

Program to compute the roots of a quadratic Equation using the quadratic formula#

program quadratic_equation_solver

! Calculates and prints the roots
! of a quadratic equation

    implicit none

    ! Variables
    !   a, b, c: coefficients
    !   x1, x2: roots

    real            :: a, b, c, x1, x2, x1_smaller, x2_smaller
    real            :: difference, percentage
    complex         :: z1, z2

    real            :: discriminant

    print *
    write (*, '(a)') "***** Quadratic Equation Solver *****"
    print *

    ! For the Jupyter Notebook, we will pipe the coefficients from the command line 
    ! Read the coefficients
    !print *, "Enter a, the coefficient of x ** 2 -->"
    !read *, a

    !print *, "Enter b, the coefficient of x -->"
    !read *, b

    !print *, "Enter c, the constant term -->"
    !read *, c
    
    ! The piped output from an echo statement will be processed by the line below
    read *, a, b, c
    
    write (*, '(a)') "The read in coefficients are:"
    write (*, '(3 (a, f8.3))') "a = ", a, "   b = ", b, "   c = ", c
    print * ! skip a line on the screen

    if (a == 1) then
        write (*, '(a, f6.3, a, f5.3)' ) "This program will solve the quadratic equation x^2 ", b, "x + ", + c
    else if ((a /= 1) .and. (b > 0)) then
        write (*, '(a, f5.3, a, f6.3, a, f5.3)') "This program will solve the quadratic equation ", a, "x^2 +", b, "x + ", c
    else if ((a /= 1) .and. (b < 0)) then
        write (*, '(a, f5.3, a, f6.3, a, f5.3)') "This program will sovle the quadratic equation ", a, "x^2 ", b, "x + ", c
    end if

    print * ! skip a line on the screen

    if ((a == 0) .and. (b == 0)) then
        ! Handle impossible case a and b both equal to zero
        write (*, '(a)') "Coefficients of a and b cannot both be zero!"
    else if ((a == 0) .and. (b /= 0)) then
        ! Handle linear case
        x1 = -c / b
        x2 = x1

        ! Print the roots
        write (*, '(a)') "Linear case: the root is:"
        write (*, '(a)') "x = ", x1

    else if ((a /= 0) .and. (b /= 0)) then
        ! Handle 2nd order cases by first calculating the discriminant
        !print * ! kips a line on the screen
        discriminant = ((b ** 2) - (4 * a * c))
        write (*, '(a, f8.3)') "The discriminant = ", discriminant
        print * ! skip a line on the screen

        if (discriminant > 0) then
        ! Calculate real, non-degenerate roots by the quadratic formula

            write (*, '(a)') "Roots are real and non-degenerate..."
            x1 = (-b + sqrt(discriminant)) / (2 * a)
            x2 = (-b - sqrt(discriminant)) / (2 * a)
        
        else if (discriminant == 0) then
        ! Calculate real, degenerate roots by the quadratic formula
            write (*, '(a)') "Roots are real and degenerate..."
            x1 = (-b + sqrt(discriminant)) / (2 * a)
            x2 = x1

        else if (discriminant < 0) then
            write (*, '(a)') "Roots are complex"
            x1 = 0
            x2 = 0
            z1 = (-b + sqrt (cmplx (discriminant))) / (2 * a)
            z2 = (-b - sqrt (cmplx (discriminant))) / (2 * a)

        end if

        ! Calculate the smaller root using x1 = c / (a * x2) and taking abs value
        if (abs(x1) < abs(x2)) then
            x1_smaller = abs(c / (a * x2))
            difference = abs(x1)- x1_smaller
            percentage = (difference / x1_smaller) * 100
        else if (abs(x1) > abs(x2)) then
            x2_smaller = abs(c / (a * x1))
            difference = abs(x2) - x2_smaller
            percentage = (difference / x2_smaller) * 100
        else if (abs(x1) == abs(x2)) then
            x1_smaller = abs (c / (a * x2))
            x2_smaller = x1_smaller
            difference = 0
            percentage = 0
        end if

        ! Print the roots
        if (discriminant >= 0) then
            print * ! skip a line on the screen
            write (*, '(a)')  "The roots are (using just sqrt):"
            write (*, '(a, f6.3)') "x1 = ", x1
            write (*, '(a, f6.3)') "x2 = ", x2
            print * ! skip a line on the screen
            ! ************

            ! ************
            write (*, '(a)') "The absolute value of the smaller root according to x2 = c/ax1 is:"

            if (abs(x1) <= abs(x2)) then
                write (*, '(a, f5.3)') "x1 = ", x1_smaller
            else if (abs(x1) >= abs(x2)) then
                write (*, '(a, f5.3)') "x2 = ", x2_smaller
            end if

            ! ************
            print * ! skip a line on the screen
            write (*, '(a, f5.3)') "The difference is: ", difference
            write (*, '(a, f5.3, a)') "The percentage difference is: ", percentage, "%"

            ! ************
        else if (discriminant < 0) then
            print * ! skip a line on the screen
            write (*, '(a)') "The roots are (using sqrt and cmplx):"
            write (*, '(a, f6.3, a, f5.3, a)') "z1 = ", real(z1), " +", aimag(z1), "i"
            write (*, '(a, f6.3, a, f6.3, a)') "z2 = ", real(z2), " ",  aimag(z2), "i"
        end if
    end if

 end program quadratic_equation_solver

The following explanation is given by “Code Copilot” within ChatGPT 4.

The Fortran program quadratic_equation_solver calculates and prints the roots of a quadratic equation of the form \(ax^2 + bx + c = 0\). The program is structured to handle different scenarios based on the values of the coefficients \(a\), \(b\), and \(c\). Here is a detailed explanation of its functionality:

Initial Setup and Input Reading#

  • The program starts with an introductory message to the user.

  • It reads the coefficients \(a\), \(b\), and \(c\) from the standard input. In the commented section, there’s an indication that in an interactive environment like Jupyter Notebook, these values would be piped directly from the command line.

Handling Different Quadratic Forms#

  • The program first checks if \(a\) equals 1 or not and formats the display of the quadratic equation accordingly. It accounts for both positive and negative \(b\) values.

Error Handling and Special Cases#

  • The program checks if both \(a\) and \(b\) are zero, which is not a valid state for a quadratic equation and prints an error message.

  • If \(a\) is zero but \(b\) is not, the equation is linear, not quadratic. It then calculates the root as \(-c/b\) and prints it.

Discriminant Calculation and Root Analysis#

  • The program calculates the discriminant \(\Delta = b^2 - 4ac\). This value determines the nature of the roots:

  • Positive Discriminant: Indicates two distinct real roots. The roots are calculated using the quadratic formula.

  • Zero Discriminant: Indicates a single repeated real root.

  • Negative Discriminant: Indicates complex roots. The program computes these using Fortran’s complex number handling capabilities.

Additional Calculations and Output#

  • The program includes logic to compute which root is smaller and attempts to verify this using a derived formula \(x = c/(ax_2)\) (however, this formula seems contextually misplaced for quadratic equations).

  • It calculates the percentage difference between the computed smaller root and the derived value, presumably to check the accuracy or stability of the numerical computations.

Final Output#

  • Depending on the discriminant, the program prints:

  • The real roots or the single real root and the calculations regarding the smaller root verification.

  • The complex roots if applicable.

Error Handling and Special Case Checks#

  • The program has checks for unusual or special input values to ensure robustness, like when both \(a\) and \(b\) are zero.

Conclusion#

This Fortran program is comprehensive in handling the different scenarios encountered when solving quadratic equations. It not only provides the roots based on the discriminant but also includes checks for special cases, such as non-quadratic conditions (linear equation) and invalid inputs. Additionally, the extra calculations for verifying the smaller root’s computation add an interesting layer of numerical analysis.

Program Compilation and Execution#

The above program is compiled and run using Fortran Package Manager (fpm):

import os
root_dir = os.getcwd()
code_dir = root_dir + "/" + "Fortran_Code/Section_1_8_Ex_2_Quadratic_Formula"
os.chdir(code_dir)
build_status = os.system("fpm build 2>/dev/null")

Find the roots for the equation
#

\[ \Large x^2 + 3x + 2 = 0 \]
exec_status = os.system("echo '1 3 2' | fpm run 2>/dev/null")
***** Quadratic Equation Solver *****

The read in coefficients are:
a =    1.000   b =    3.000   c =    2.000

This program will solve the quadratic equation x^2  3.000x + 2.000

The discriminant =    1.000

Roots are real and non-degenerate...

The roots are (using just sqrt):
x1 = -1.000
x2 = -2.000

The absolute value of the smaller root according to x2 = c/ax1 is:
x1 = 1.000

The difference is: 0.000
The percentage difference is: 0.000%

Find the roots for the equation
#

\[ \Large x^2 + 2x + 1 = 0 \]
exec_status = os.system("echo '1 2 1' | fpm run 2>/dev/null")
***** Quadratic Equation Solver *****

The read in coefficients are:
a =    1.000   b =    2.000   c =    1.000

This program will solve the quadratic equation x^2  2.000x + 1.000

The discriminant =    0.000

Roots are real and degenerate...

The roots are (using just sqrt):
x1 = -1.000
x2 = -1.000

The absolute value of the smaller root according to x2 = c/ax1 is:
x1 = 1.000

The difference is: 0.000
The percentage difference is: 0.000%

Find the roots for the equation
#

\[ \Large x^2 + 5x + 9 = 0 \]
exec_status = os.system("echo '1 5 9' | fpm run 2>/dev/null")
***** Quadratic Equation Solver *****

The read in coefficients are:
a =    1.000   b =    5.000   c =    9.000

This program will solve the quadratic equation x^2  5.000x + 9.000

The discriminant =  -11.000

Roots are complex

The roots are (using sqrt and cmplx):
z1 = -2.500 +1.658i
z2 = -2.500 -1.658i

Find the roots for the equation
#

\[ \Large x^2 + 6x + 1 = 0 \]
exec_status = os.system("echo '1 6 1' | fpm run 2>/dev/null")
***** Quadratic Equation Solver *****

The read in coefficients are:
a =    1.000   b =    6.000   c =    1.000

This program will solve the quadratic equation x^2  6.000x + 1.000

The discriminant =   32.000

Roots are real and non-degenerate...

The roots are (using just sqrt):
x1 = -0.172
x2 = -5.828

The absolute value of the smaller root according to x2 = c/ax1 is:
x1 = 0.172

The difference is: 0.000
The percentage difference is: 0.000%