Skip to content

Instantly share code, notes, and snippets.

@kvedala
Last active September 23, 2025 09:06
Show Gist options
  • Save kvedala/9713842d5e264c94e293a930b479f597 to your computer and use it in GitHub Desktop.
Save kvedala/9713842d5e264c94e293a930b479f597 to your computer and use it in GitHub Desktop.
Durand-Kerner Roots - Python
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@sergiovaneg
Copy link

Thank you so much for doing this! I was a bit lost after reading the Wikipedia article, but this write-up made it so much clearer. I would also like to propose an alternative implementation that, even if not 100% equivalent, makes the computation a lot more SIMD-friendly (the actual SIMD implementation is missing, though):

import numpy as np


def durand_kerner(
        p: np.ndarray,
        max_iter: int = 1000,
        tol: float = 1e-8
) -> np.ndarray:
    # Polynomial scaling (roots remain unchanged)
    p = p / p[0]

    # Deterministic init using the complex unit circle
    deg = len(p) - 1
    roots = np.exp(np.arange(deg) * 2j * np.pi / deg)

    f0, cnt = np.polyval(p, roots), 0
    avg_delta = tol + 1  # do-while enforcing
    while avg_delta > tol and cnt < max_iter:
        cnt += 1

        # Simultaneous distance calculation using advanced indexing
        dens = np.prod(roots[:, None] - roots[None, :] + np.eye(deg), axis=1)
        roots = roots - f0 / dens

        f1 = np.polyval(p, roots)
        # 2-norm of the change in polyval
        avg_delta = np.sqrt(np.sum((f1 - f0)**2) / deg)
        f0 = f1

    return roots

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment