[docs]@jit(nopython=True,cache=const.use_numba_cache)defsolve(a:float,b:float,c:float)->tuple[float,float]:"""Solve a quadratic equation :math:`A t^2 + B t + C = 0` (just-in-time compiled)"""ifnp.abs(a)<const.EPS:ifnp.abs(b)<const.EPS:returnmath.nan,math.nanu=-c/breturnu,ubp=b/2delta=bp*bp-a*cu1=(-bp-delta**0.5)/au2=-u1-b/areturnu1,u2
# TODO: In the branch `3d`, which will eventually be merged into main, this function has# replaced `solve`.
[docs]@jit(nopython=True,cache=const.use_numba_cache)defsolve_complex(a:float,b:float,c:float)->NDArray[np.complex128]:_a=complex(a)_b=complex(b)_c=complex(c)roots=np.full(2,np.nan,dtype=np.complex128)ifabs(_a)!=0:# Quadratic cased=_b*_b-4*_a*_csqrt_d=cmath.sqrt(d)# Sign trick to reduce catastrophic cancellationsign_b=1.0if_b.real>=0else-1.0r1_num=-_b-sign_b*sqrt_dr1_den=2*_a# Fallback if numerator is tinyifabs(r1_num)<1e-14*abs(r1_den):r1_num=-_b+sign_b*sqrt_dr1=r1_num/r1_den# Use product identity for x2ifabs(r1)<1e-14:r2=(-_b+sqrt_d)/(2*_a)else:r2=(_c/_a)/r1roots[0]=r1roots[1]=r2returnrootsifabs(_b)!=0:# Linear caser1=-_c/_broots[0]=r1returnroots# Equation is just c=0. Either zero or infinite solutions. Returns nansreturnroots