Cómo Resolver Ecuaciones de Segundo Grado en Python

Cómo Resolver Ecuaciones de Segundo Grado en Python

Si las ecuaciones de segundo grado son un problema clásico de las Matemáticas, también lo son, sin duda, de la Programación. Su resolución se trata de un ejercicio ideal para aquellos que están comenzando a programar, pues implica entrada de datos por teclado, salida por pantalla, cálculos aritméticos y condicionales. ¿Quieres conocer la manera de resolver ecuaciones de segundo grado en Python? Te lo cuento de manera detallada en este artículo.

Suponiendo la ecuación ax² + bx + c = 0:

  1. Calcula el discriminante: disc = b * b - 4 * a * c
  2. Si disc es negativo la ecuación no tiene solución
  3. Si disc no es negativo, calcula su raíz: raiz = srqt(disc)
  4. Calcula las soluciones: x_1 = (-b + raiz) / (2 * a) y x_2 = (-b - raiz) / (2 * a)

A continuación te cuento paso a paso la manera de resolver ecuaciones cuadráticas parándome en cada detalle para que lo entiendas a la perfección.

Obteniendo los valores de los coeficientes

El primer paso es obtener los valores de los coeficientes. Si bien es cierto que en una aplicación real en la que se necesitase resolver ecuaciones de segundo grado estos coeficientes provendrían de ficheros, bases de datos o de otros módulos de cálculo, en este ejemplo vamos a obtenerlos directamente del usuario, a través del teclado.

Para obtener un valor proporcionado por el usuario puedes utilizar la función input, que se queda esperando a que el usuario introduzca un valor y pulse la tecla enter. El valor proporcionado por el usuario lo devuelve la función como una cadena de texto que solo tenemos que convertir a número decimal mediante la función float.

En este caso tendremos que pedir al usuario tres valores, pues tres son los coeficientes que se manejan en una ecuación de segundo grado que, como sabes, tiene la siguiente forma: ax² + bx + c = 0, siendo x la incógnita a calcular y a, b y c los coeficientes.

Ten en cuenta que la ecuación de segundo grado no está definida si el coeficiente a es 0, por lo que podemos asumir que el valor de dicho coeficiente siempre será diferente de 0.

Es posible, además, que el usuario no introduzca valores numéricos cuando se le pidan. Esto sería algo que habría que comprobar en nuestro programa para evitar que se rompa la ejecución del mismo. No lo voy a contar aquí para no hacer este artículo demasiado largo, pero te explico en otro cómo pedir un valor al usuario hasta que sea válido. Siguiendo las indicaciones de dicho artículo podrías comprobar tanto que el coeficiente a es diferente de 0 como que los valores introducidos son de tipo numérico.

Así, para este programa vamos a suponer que el usuario siempre introduce valores correctos para los coeficientes a, b y c. La manera de solicitarlos sería la siguiente:

a = float(input('Dame el valor del coeficiente a: '))
b = float(input('Dame el valor del coeficiente b: '))
c = float(input('Dame el valor del coeficiente c: '))

Este código muestra por pantalla el mensaje pasado por parámetro a la función input y se queda esperando a que el usuario introduzca un valor. Una vez es recibido el valor, input lo devuelve y acto seguido es convertido a tipo float con la función del mismo nombre y asignado a una variable.

Si te fijas, este código es un poco repetitivo así que vamos a hacer uso de distintas características de Python para evitar dicha repetición. Esta parte es opcional así que si quieres, puedes continuar con el siguiente apartado en donde empezamos a hacer cálculos, pero ten en cuenta que más adelante, donde te presento el código completo hago uso de estas optimizaciones.

Para mejorar este código voy a utilizar las características de comprensión de listas y de desempaquetado.

La compresión de listas nos permite crear una lista de valores, que en nuestro caso serán los tres coeficientes, mediante un bucle de manera muy sencilla en una sola línea. Por otro lado, el desempaquetado nos permitirá sacar los valores de la lista generada y almacenarlos directamente en tres variables.

Te cuento cómo funciona la comprensión de listas en estos dos artículos que tratan sobre el uso de paréntesis, corchetes y llaves en Python y sobre cómo filtrar listas en Python.

Así, puedo generar una lista con tres valores (los tres coeficientes) mediante el siguiente código:

[float(input(f'Dame el coeficiente {coef}: ')) for coef in ('a', 'b', 'c')]

En el código anterior recorro con un bucle for la tupla (‘a’, ‘b’, ‘c’) haciendo un llamada a input (y su correspondiente llamada a float) para cada uno de sus valores. Finalmente, los valores obtenidos se almacenan en la lista gracias a la comprensión (fíjate en los corchetes [ y ] que rodean toda la sentencia.

Ahora es el turno del desempaquetado. Te hablo del desempaquetado de listas, y en general de iterables, en este otro artículo sobre el uso de asterisco * y doble asterisco ** en Python.

Así, si por ejemplo realizo lo siguiente a, b, c = [1, 2, 3], es fácil ver que los valores 1,2 y 3 irán a parar respectivamente a las variables a, b y c y en este orden.

Combinando ahora las dos instrucciones anteriores, podemos obtener del usuario los tres coeficientes para nuestra ecuación sin necesidad de repetir código y en una única línea (eso sí, asumiendo, al igual que antes, que los valores introducidos por el usuario serán válidos):

a, b, c = [float(input(f'Dame el coeficiente {coef}: ')) for coef in ('a', 'b', 'c')]

Podríamos, simplemente, quedarnos con la lista y seguir trabajando con los valores almacenados en ella, pero el código resultaría más difícil de leer y menos intuitivo.

Calculando el discriminante

Una vez que tenemos lo valores ya podemos empezar a hacer cálculos. La manera universal de resolver ecuaciones de segundo grado pasa por aplicar la llamada fórmula de Bhaskara que tiene este aspecto:

Fórmula de resolución de ecuaciones de segundo grado
Fórmula para la resolución de ecuaciones de segundo grado

Si te paras a analizarla puedes ver que hay que calcular la raíz cuadrada de la expresión b² - 4ac. La raíz cuadrada no está definida para números negativos. Por este motivo, si dicha expresión, que llamaremos discriminante, es un valor negativo, la raíz no se puede calcular y la ecuación de segundo grado no tiene solución real (aunque sí la tiene en el dominio de los números complejos que se escapa del ámbito de este artículo).

Esta es una situación con la que tenemos que lidiar, por tanto, lo primero que debemos hacer es calcular el valor del discriminante, cosa que hacemos de manera muy sencilla:

discriminante =  b * b - 4 * a * c

El cálculo del cuadrado de un valor es muy sencillo de obtener multiplicando dicho valor por sí mismo. Así, si queremos obtener el valor de b al cuadrado, es decir , podemos hacer b * b, como puedes ver en el código anterior.

Python también dispone de un operador para calcular potencias que es el doble asterisco **, de forma que también podrías calcular el cuadrado de b de la siguiente manera: b ** 2.

Ecuaciones de segundo grado sin solución

Como te acabo de contar, hay ecuaciones de segundo grado que no tienen solución, cosa que sucede cuando el discriminante es negativo.

Es necesario realizar esta comprobación que, en caso de cumplirse, nos obligará a mostrarle al usuario un mensaje de error indicándole que la ecuación proporcionada no tiene solución.

Esto se hace de manera muy sencilla con un condicional:

discriminante =  b * b - 4 * a * c

if discriminante < 0:
    print('La ecuación no tiene solución.')

Si el discriminante resulta ser mayor o igual que cero, sí tendremos solución y solo quedará calcularla como vemos a continuación.

Calculando las soluciones (o la solución)

Puede suceder que una ecuación cuadrada tenga dos soluciones diferentes. Esto es posible debido a que el cuadrado de cualquier número es siempre un número positivo ya que un número negativo multiplicado por otro número negativo da como resultado uno positivo. Esto es, existen números diferentes que elevados al cuadrado resultan en el mismo número.

Dicho de otra manera, el resultado de una raíz cuadrada en realidad, son siempre dos, que es la magnitud resultado de la operación con signo positivo y con signo negativo.

Para que quede claro, si hacemos la raíz cuadrada de 4 obtenemos 2. Pero el resultado de la raíz no es solo 2, sino que también es -2, ya que 2² = 4 y (-2)² = 4.

Esto también tenemos que considerarlo para calcular la solución de la ecuación, de forma que tendremos que obtener dos valores diferentes: uno teniendo en cuenta el resultado positivo de la raíz y otro teniendo en cuenta el negativo.

Para ello, y siempre suponiendo que el discriminante es un número no negativo, podemos calcular las dos soluciones diferentes de la ecuación de la siguiente manera:

raiz = sqrt(discriminante)
x_1 = (-b + raiz) / (2 * a)
x_2 = (-b - raiz) / (2 * a)

Fíjate en que calculo primero el valor positivo de la raíz haciendo uso de la función sqrt que está ubicada en el módulo math. Recuerda hacer un from math import sqrt para poder usarla. El motivo de calcularlo previamente, al igual que con anterioridad también he almacenando el valor del discriminante en una variable, es evitar la repetición de código a la hora de calcular las dos soluciones x_1 y x_2. Así, además, logramos un código más claro, sencillo de leer y menos propenso a errores.

Ahora bien, puede suceder que x_1 y x_2 tengan el mismo valor. Es decir, que la ecuación tiene una única solución (a veces se le llama a esto solución doble). Esto sucede cuando el discriminante es 0 pues el resultado de la raíz también sería 0 y no habría diferencia entre las expresiones para el cálculo de x_1 y x_2, con lo que resultarían iguales.

Es interesante también distinguir esta situación. Para ello basta con realizar la comprobación de que el discriminante es 0 y así calcular la única solución en ese caso. Puedes hacerlo de la siguiente manera:

raiz = sqrt(discriminante) 
x_1 = (-b + raiz) / (2 * a)      # calculamos una primera solución
if discriminante != 0:           # comprobamos si hay otra solución
    x_2 = (-b - raiz) / (2 * a)  # calculamos la segunda solución

Solo quedaría ahora mostrar las soluciones por pantalla. Lo vemos a continuación juntando todo el código que ya hemos visto.

Código completo

Vamos a ver cómo queda todo juntando los distintos fragmentos de código que hemos ido viendo y mostrando algunos mensajes por pantalla al usuaio. Añado comentarios al código para te quede claro qué se hace en cada línea:

from math import sqrt

# mostramos un mensaje de bienvenida
print('¡Hola! Vamos a resolver una ecuación de segundo grado:')
print('    ax² + bx + c = 0\n')

# pedimos los coeficientes al usuario
a, b, c = [float(input(f'Dame el coeficiente {coef}: ')) for coef in ('a', 'b', 'c')]

# calculamos el discriminante
discriminante =  b * b - 4 * a * c

if discriminante < 0: # comprobamos si no existen soluciones reales
    print(f'La ecuación no tiene soluciones reales.')
else:
    raiz = sqrt(discriminante)      # calculamos la raíz
    x_1 = (-b + raiz) / (2 * a)     # calculamos una primera solución
    if discriminante != 0:          # comprobamos si hay otra solución
        x_2 = (-b - raiz) / (2 * a) # calculamos la segunda solución
        print(f'Las soluciones son {x_1} y {x_2}.') # mostramos las dos soluciones
    else:
        print(f'La única solución es x = {x_1}') # mostramos la única solución

Ya ves que, tras las explicaciones previas, el código completo queda sencillo y conciso. Vamos a ver la traza de algunas ejecuciones para que veas cómo funciona. La primera de ellas es una ejecución en la que la ecuación de segundo grado a resolver tiene dos soluciones diferentes (es decir, el discriminante es mayor que 0):

¡Hola! Vamos a resolver una ecuación de segundo grado:
     ax² + bx + c = 0
 Dame el coeficiente a: 2.25
 Dame el coeficiente b: 1.5
 Dame el coeficiente c: -2
 Las soluciones son 0.6666666666666666 y -1.3333333333333333.

Vamos a ver ahora un caso en donde solo hay una solución (o solución doble, con el discriminante igual a 0):

¡Hola! Vamos a resolver una ecuación de segundo grado:
     ax² + bx + c = 0
 Dame el coeficiente a: -2
 Dame el coeficiente b: 4
 Dame el coeficiente c: -2
 La única solución es x = 1.0

Y, finalmente, veremos una traza en la que no existe solución real pues el discriminante es negativo:

¡Hola! Vamos a resolver una ecuación de segundo grado:
     ax² + bx + c = 0
 Dame el coeficiente a: 1
 Dame el coeficiente b: 2
 Dame el coeficiente c: 3
 La ecuación no tiene soluciones reales.

Creando una función para la resolución de ecuaciones cuadradas

Vamos a encapsular ahora nuestro código dentro de una función que reciba los coeficientes a, b y c y nos devuelva la solución o soluciones de la ecuación. Esto es interesante si necesitamos resolver varias ecuaciones en nuestro programa.

Pensaremos la función para que nos devuelva una lista de valores ya que, como hemos visto, las soluciones reales posibles pueden ser 0, 1 o 2. De esta manera, basta con revisar la longitud de la lista devuelta por nuestra función para conocer el número de soluciones de la ecuación.

Ahora bien, la función no debe mostrar nada por pantalla, de eso nos ocuparemos después de llamar a nuestra función, así que eliminaremos las llamadas a la función print y sustituiremos las del final por instrucciones para añadir las soluciones calculadas a la lista de soluciones.

Además, como nuestra función ya recibe los valores de los coeficientes como parámetros no necesitamos tampoco hacer llamadas a input dentro de ella. Veamos el código:

from math import sqrt

def resolver_ecuacion_cuadrada(a, b, c):
    soluciones = [] # creamos una lista vacía para las soluciones

    discriminante = b * b - 4 * a * c

    if discriminante >= 0:  # comprobamos si existen soluciones reales
        raiz = sqrt(discriminante)
        soluciones.append((-b + raiz) / (2 * a))    # calculamos una primera solución
        if discriminante != 0:
           soluciones.append((-b - raiz) / (2 * a)) # calculamos la segunda solución si existe

    return soluciones

Con nuestra nueva función resolver_ecuacion_cuadrada realizamos una ejecución del código siguiente. Fíjate en que, aunque podríamos solicitar al usuario los valores de los coeficientes como hacíamos previamente, en este caso vamos a proporcionárselos directamente:

soluciones = resolver_ecuacion_cuadrada(1.17, -4.48, -0.5)
print(soluciones)

soluciones = resolver_ecuacion_cuadrada(4, -3, 1)
print(soluciones)

soluciones = resolver_ecuacion_cuadrada(5, 1, 0)
print(soluciones)

Si directamente imprimimos el contenido de la lista de soluciones proporcionado por nuestra función obtenemos lo siguiente, donde puedes observar que para el primer caso tenemos dos soluciones, para el segundo ninguna solución y para el tercero dos soluciones:

[3.9375907690225196, -0.10853093996269035]
[]
[0.0, -0.2]

Comprobando las soluciones

De manera complementaria, realicemos ahora otra función que nos sirva para comprobar si un número es una solución válida, es decir, una x válida, para una ecuación cuadrada dada.

Para esto, necesitamos definir una función que reciba cuatro parámetros diferentes, donde tres de ellos serán los coeficientes a, b y c y el otro el valor de la x a comprobar.

Lo que tendrá que hacer esta función será sustituir esos cuatro valores en la expresión general de ecuación cuadrada ax² + bx + c = 0 y comprobar que se cumple la igualdad.

Hay que tener en cuenta que debemos realizar una comparación de números reales. Siempre que tengamos que hacer esto debemos determinar un pequeño margen de error admisible dentro del cual podemos considerar que dos números reales son iguales. Esto es debido a que, por ejemplo, los dos números 1.000000 y 1.000001 son diferentes si los comparamos con el comparador de igualdad ==, pero en nuestro caso quizá los queramos considerar con números iguales.

Así definiendo la variable margen como ese pequeño margen de error, por ejemplo, 0.0001 (una diezmilésima), nuestro código tendrá que considerar que dos números cuya resta en valor absoluto (para eliminar el signo negativo del resultado) sea inferior a dicho margen son iguales. Así, y suponiendo los números d y e, nuestra comparación ya no será d == e, sino abs(d - e) <= margen.

El código de nuestra función para comprobar si una solución es válida quedaría de la siguiente manera:

def solucion_valida(x, a, b, c, margen=0.0001):
    return abs(a * x * x + b * x + c) < margen

En este caso, como el valor a la derecha de la igualdad en la expresión general ax² + bx + c = 0 es 0, nos podemos ahorrar la resta y comprar el valor de la subexpresión a la izquierda de la igualdad con el margen proporcionado.

Fíjate en que le doy un valor por defecto al parámetro margen para no tener que indicarlo yo en cada llamada a la función solucion_valida. Puedes aprender más sobre parámetros posicionales y parámetros con nombre en este artículo sobre el uso de asteriscos en Python.

Vamos a probar nuestra función con algunos ejemplos para comprobar su funcionamiento:

print(solucion_valida(3.9375, 1.17, -4.48, -0.5, margen=0.001))
print(solucion_valida(0, 5, 1, 0))
print(solucion_valida(2, 5, 1, 0))
print(solucion_valida(0, 4, -3, 1))

Como puedes ver, en el primer caso varío el margen a mi gusto. En el resto de casos dejo el valor de margen por defecto. El resultado de la ejecución de este código es:

True
True
False
False

Y esto es todo. Espero haber arrojado algo de luz y que haya sido ilustrativo este ejemplo clásico para el aprendizaje de programación.

La Hoja de Referencia de Python – ¡Gratis!

La Hoja de Referencia de Python - Código Pitón
Consigue trucos, consejos y actualizaciones y, por supuesto, la Hoja de Referencia de Python gratis.



Antes de suscribirte consulta aquí la Información Básica sobre Protección de Datos. Responsable de los datos: Laura Otero Moreira. Finalidad de la recogida y tratamiento de los datos personales: enviarte boletín informativo de Python y comunicaciones comerciales. Legitimación: tu consentimiento. Destinatarios: no se ceden a terceros. Los datos se almacenan en los servidores de marketing (MailRelay). Derechos: podrás ejercer tus derechos de acceso, rectificación, limitación y supresión de datos en info @ codigopiton.com así como presentar una reclamación ante una autoridad de control. Más información en nuestra política de privacidad, encontrarás información adicional sobre la recopilación y el uso de tu información personal, incluida información sobre acceso, conservación, rectificación, eliminación, seguridad y otros temas.