## 1. Overview

A quadratic equation is a second-degree polynomial equation in a single variable, typically written in the form:

`ax^2 + bx + c = 0`

We can find such equations in various real-world applications in finance, computer graphics, academics, etc. So, it’s a fundamental mathematical operation with diverse applications to know.

In this tutorial, **we’ll explore a few approaches to finding the roots of a quadratic equation in Kotlin**.

## 2. Algorithm

Let’s take a quadratic equation with *a*, *b*, and *c* as the coefficient constants for the polynomial terms in decreasing order of degree:

`a*x^2 + b*x + c = 0`

Now, the next step is to find the discriminant (*D*) in terms of the three coefficients:

`D = b^2 - 4*a*c`

It’s important to note that the **discriminant (***D*) plays a significant role in deciding the nature of roots for the quadratic equation:

- When
*D>0*, both the roots are real numbers
- When
*D<0*, both the roots are complex numbers with an imaginary component
- When D==0, both the roots are real numbers with the same value

Further, we can express the roots in terms of the discriminant (*D*) and coefficients:

```
root1 = (-b + √D) / (2a)
root2 = (-b - √D) / (2a)
```

Lastly, we can assume that *a!=0* for the equation to be quadratic, as the coefficient of the highest degree term needs to be non-zero. As a result, we can safely divide by *a* while computing the roots.

## 3. Solving for Real Roots

In this section, we’ll keep things simple and **implement the algorithm for scenarios when the roots are real numbers**.

### 3.1. *QuadraticEquationSolver* Class

Let’s start by writing the barebone class, *QuadraticEquationSolver*, with three properties, *a*, *b*, and *c*, denoting the coefficients of the quadratic equation:

```
class QuadraticEquationSolver(val a: Double, val b: Double, val c: Double) {
// ToDo: Add solutions
}
```

We must note that the properties, namely, *a*, *b*, and *c*, will be initialized through the primary constructor. Further, we intend to add the solution for finding roots within this class.

### 3.2. Solving for Real Roots

Now, let’s go ahead and **write the ***solveForRealRoots()* function within the *QuadraticEquationSolver* class to compute the real roots for the equation:

```
fun solveForRealRoots(): Pair<Double, Double>? {
val discriminant = b * b - 4 * a * c
if (discriminant < 0) {
// No real roots
return null
}
val root1 = (-b + sqrt(discriminant)) / (2 * a)
val root2 = (-b - sqrt(discriminant)) / (2 * a)
return Pair(root1, root2)
}
```

It’s worth noting that** we check for the value of the ***discriminant* to be non-negative before finding the real roots. Moreover, we return a *Pair* of *root1* and *root2*.

Lastly, let’s compute the roots of the equation *x^2 + 2*x + 1 = 0* and verify that our function is giving the correct results:

```
val solver = QuadraticEquationSolver(1.0, 2.0, 1.0)
val expectedRoots = Pair(-1.0, -1.0)
val actualRoots = solver.solveForRealRoots()
Assertions.assertEquals(expectedRoots, actualRoots)
```

As expected, we’ve got the correct roots using this approach.

## 4. Solving for Complex Roots

In this section, let’s learn how to **implement the algorithm to compute complex roots** for a quadratic equation.

### 4.1. Commons Math Library

To support arithmetic operations for complex numbers, we’ll use the *commons-math3* library. So, let’s go ahead and add its dependency to the *pom.xml* file in our project:

```
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId>
<version>3.6.1</version>
</dependency>
```

After adding the dependency, we can use the *Complex* class from the *org.apache.commons.math3.complex* package to carry out arithmetic operations for complex numbers conveniently.

### 4.2. Complex Roots

Let’s go ahead and write the *solveForComplexRoots()* function to return a *Pair* of *Complex* roots for a quadratic equation:

```
fun solveForComplexRoots(): Pair<Complex, Complex>? {
val discriminant = Complex(b * b - 4 * a * c)
val sqrtDiscriminant = discriminant.sqrt()
val root1 = (Complex(-b).add(sqrtDiscriminant)).divide(Complex(2 * a))
val root2 = (Complex(-b).subtract(sqrtDiscriminant)).divide(Complex(2 * a))
return Pair(root1, root2)
}
```

We can see that our approach **no longer needs to check whether the discriminant is non-zero**. Further, we’ve used the *sqrt()*, *add()*, *subtract()*, and *divide()* functions from the *Complex* class for performing arithmetic operations.

Next, let’s use the *solveForComplexRoots()* to find the real roots for the equation *x^2 + 2*x + 1 = 0*:

```
val solver = QuadraticEquationSolver(1.0, 2.0, 1.0)
val expectedRoots = Pair(Complex(-1.0), Complex(-1.0))
val actualRoots = solver.solveForComplexRoots()
Assertions.assertEquals(expectedRoots, actualRoots)
```

It’s important to remember that all real numbers are a subset of complex numbers. So, we can use *solveForComplexRoots()* for any generic quadratic equation.

Lastly, let’s **verify that it works for the equation ***x^2 + x + 1 = 0,* which has complex roots with imaginary components:

```
val solver = QuadraticEquationSolver(1.0, 1.0, 1.0)
val expectedRoots = Pair(Complex(-0.5, Math.sqrt(3.0) * 0.5), Complex(-0.5, -1 * Math.sqrt(3.0) * 0.5))
val actualRoots = solver.solveForComplexRoots()
Assertions.assertEquals(expectedRoots, actualRoots)
```

Great! We’ve got this one right.

## 5. Conclusion

In this article, **we learned about the basics of a quadratic equation and how to find its roots**. Furthermore, we explored two scenarios where roots can be real numbers or complex numbers with an imaginary component, respectively.

As always, the code from this article is available over on GitHub.