Python для решения квадратных уравнений: эффективные алгоритмы

Раздел: Численные методы -> Математические вычисления

Решение квадратного уравнения в Python

Как найти корни квадратного уравнения с помощью дискриминанта?

Наиболее распространённый способ основан на вычислении дискриминанта. Для уравнения вида ax2 + bx + c = 0 дискриминант D = b2 - 4ac. При D > 0 два действительных корня, при D = 0 один корень, при D < 0 корни комплексные.


import math

def solve_quadratic(a, b, c):
    if a == 0:
        if b == 0:
            return ('бесконечно много корней' if c == 0 else 'нет корней')
        else:
            return (-c / b,)
    D = b**2 - 4*a*c
    if D > 0:
        x1 = (-b + math.sqrt(D)) / (2*a)
        x2 = (-b - math.sqrt(D)) / (2*a)
        return (x1, x2)
    elif D == 0:
        x = -b / (2*a)
        return (x,)
    else:
        real = -b / (2*a)
        imag = math.sqrt(-D) / (2*a)
        return (complex(real, imag), complex(real, -imag))
    

Python решение примера (решение примера на python)

Функция обрабатывает все случаи: вырожденный, линейный, два действительных корня, один корень и комплексные. Возвращается кортеж корней.

Типичные ошибки:

  • Забыть проверить a == 0. Без проверки деление на ноль.
  • Использовать math.sqrt для отрицательного дискриминанта. Ошибка ValueError. Решение: использовать cmath.sqrt или брать корень модуля.
  • Потеря точности при b2 >> 4ac. Альтернативная формула описана в расширенных примерах.

Как решить квадратное уравнение без импорта модуля math?

Оператор ** с показателем 0.5 извлекает квадратный корень, в том числе из отрицательных чисел (возвращается комплексное число).


def solve_quadratic_no_math(a, b, c):
    if a == 0:
        if b == 0:
            return ('бесконечно много корней' if c == 0 else 'нет корней')
        return (-c / b,)
    D = b**2 - 4*a*c
    sqrt_D = D ** 0.5
    x1 = (-b + sqrt_D) / (2*a)
    x2 = (-b - sqrt_D) / (2*a)
    return (x1, x2)
    

Python вычисление значения выражений (вычисление значения выражений в python)

Подходит для минимизации зависимостей, но менее точен для комплексных корней из-за представления с плавающей точкой.

Проблема: При D, близком к нулю, могут появиться два почти равных корня. Решение: проверка abs(D) < 1e-12 и приравнивание к нулю.

Как воспользоваться библиотекой NumPy для нахождения корней?

Функция numpy.roots принимает список коэффициентов в порядке убывания степени.


import numpy as np
coeff = [a, b, c]
roots = np.roots(coeff)
    

вычисление функции в python (вычисление значения функции в python)

Удобно для массовых вычислений. Требует предварительной обработки случая a=0.

При a=0 и b=0 np.roots может выдать ошибку. Необходима отдельная проверка.

Как обрабатывать комплексные корни с помощью модуля cmath?

cmath.sqrt корректно извлекает корень из отрицательного числа.


import cmath

def solve_quadratic_cmath(a, b, c):
    if a == 0:
        if b == 0:
            return ('бесконечно много корней' if c == 0 else 'нет корней')
        return (-c / b,)
    D = b**2 - 4*a*c
    sqrt_D = cmath.sqrt(D)
    x1 = (-b + sqrt_D) / (2*a)
    x2 = (-b - sqrt_D) / (2*a)
    return (x1, x2)
    

Python вычисление корня (вычисление квадратного корня в python)

Единообразный код для любого знака дискриминанта. Результат всегда комплексный.

Как решить квадратное уравнение с учётом погрешностей чисел с плавающей точкой?

Введение допуска epsilon для сравнения дискриминанта с нулём.


def solve_quadratic_eps(a, b, c, eps=1e-12):
    if a == 0:
        # обработка...
        pass
    D = b**2 - 4*a*c
    if abs(D) < eps:
        D = 0.0
    # далее обычная логика
    

Позволяет избежать деления на очень малую величину. Выбор epsilon требует учёта масштаба коэффициентов.

Слишком большое epsilon может объединить близкие корни.

- Python вычислить строку (вычисление выражения из строки в python)
- возвести в квадрат python (возведение числа в квадрат в python)
- площадь python (вычисление площади в python)

Продвинутые примеры решения квадратных уравнений в Python

Ниже приведены усложнённые варианты реализации, необходимые в специфических задачах численных методов.

Пример 1. Устойчивое вычисление корней при большом b

Используется альтернативная формула: сначала находится устойчивый корень, затем второй через теорему Виета.

Пример

import math

def solve_quadratic_stable(a, b, c):
    if a == 0:
        return (-c / b,) if b != 0 else ('беск. корней' if c == 0 else 'нет корней')
    D = b*b - 4*a*c
    if D < 0:
        sqrt_D = complex(0, math.sqrt(-D))
        x1 = (-b + sqrt_D) / (2*a)
        x2 = (-b - sqrt_D) / (2*a)
        return (x1, x2)
    sqrt_D = math.sqrt(D)
    sign = 1 if b >= 0 else -1
    x1 = (-b - sign*sqrt_D) / (2*a)
    x2 = c / (a * x1) if x1 != 0 else 0
    return (x1, x2)

print(solve_quadratic_stable(1, 1e9, 1))
(-1e-09, -1000000000.0)

Пример 2. Символьное решение с помощью SymPy

Библиотека SymPy позволяет получить аналитическое выражение для корней.

Пример

from sympy import symbols, solve, Eq

x, a, b, c = symbols('x a b c')
equation = Eq(a*x**2 + b*x + c, 0)
sol = solve(equation, x)
sol
[(-b - sqrt(b**2 - 4*a*c))/(2*a), (-b + sqrt(b**2 - 4*a*c))/(2*a)]

Пример 3. Работа с рациональными коэффициентами (дроби)

Использование fractions.Fraction для точности при рациональных коэффициентах.

Пример

from fractions import Fraction
import math

def solve_quadratic_fraction(a_frac, b_frac, c_frac):
    a = Fraction(a_frac)
    b = Fraction(b_frac)
    c = Fraction(c_frac)
    if a == 0:
        return (-c / b,) if b != 0 else ('беск. корней' if c == 0 else 'нет корней')
    D = b*b - 4*a*c
    sqrt_D = math.sqrt(float(D))
    x1 = (-b + sqrt_D) / (2*a)
    x2 = (-b - sqrt_D) / (2*a)
    return (x1, x2)

print(solve_quadratic_fraction(1, 0, -4))
(2.0, -2.0)

Пример 4. Использование dataclass для организации результата

Структурированный объект с полями: корни, дискриминант, тип решения.

Пример

from dataclasses import dataclass
from typing import Union, Tuple

@dataclass
class QuadraticResult:
    roots: Tuple[Union[float, complex], ...]
    discriminant: float
    root_type: str

def solve_quadratic_dataclass(a, b, c):
    if a == 0:
        if b == 0:
            if c == 0:
                return QuadraticResult((), 0, 'degenerate')
            else:
                return QuadraticResult((), 0, 'no roots')
        else:
            return QuadraticResult((-c/b,), 0, 'linear')
    D = b*b - 4*a*c
    if D >= 0:
        sqrt_D = D**0.5
        x1 = (-b + sqrt_D) / (2*a)
        x2 = (-b - sqrt_D) / (2*a)
        root_type = 'real' if D > 0 else 'double'
        return QuadraticResult((x1, x2), D, root_type)
    else:
        sqrt_D = (-D)**0.5
        real = -b / (2*a)
        imag = sqrt_D / (2*a)
        c1 = complex(real, imag)
        c2 = complex(real, -imag)
        return QuadraticResult((c1, c2), D, 'complex')

result = solve_quadratic_dataclass(1, -3, 2)
print(result)
QuadraticResult(roots=(2.0, 1.0), discriminant=1.0, root_type='real')

Решение квадратного уравнения в Python - comments

En
Python квадратное уравнение (python)