"""
    Falsi()

A non-allocating regula falsi method.
"""
struct Falsi <: AbstractBracketingAlgorithm end

function SciMLBase.__solve(
        prob::IntervalNonlinearProblem, alg::Falsi, args...;
        maxiters = 1000, abstol = nothing, verbose = NonlinearVerbosity(), kwargs...
    )
    @assert !SciMLBase.isinplace(prob) "`False` only supports out-of-place problems."

    if verbose isa Bool
        if verbose
            verbose = NonlinearVerbosity()
        else
            verbose = NonlinearVerbosity(None())
        end
    elseif verbose isa AbstractVerbosityPreset
        verbose = NonlinearVerbosity(verbose)
    end

    f = Base.Fix2(prob.f, prob.p)
    l, r = prob.tspan # don't reuse these variables
    left, right = prob.tspan
    fl, fr = f(left), f(right)

    abstol = NonlinearSolveBase.get_tolerance(
        left, abstol, promote_type(eltype(left), eltype(right))
    )

    if iszero(fl)
        return build_exact_solution(prob, alg, left, fl, ReturnCode.ExactSolutionLeft)
    end

    if iszero(fr)
        return build_exact_solution(prob, alg, right, fr, ReturnCode.ExactSolutionRight)
    end

    if sign(fl) == sign(fr)
        @SciMLMessage(
            "The interval is not an enclosing interval, opposite signs at the \
        boundaries are required.",
            verbose, :non_enclosing_interval
        )
        return build_bracketing_solution(prob, alg, left, fl, left, right, ReturnCode.InitialFailure)
    end

    i = 1
    while i ≤ maxiters
        if Impl.nextfloat_tdir(left, l, r) == right
            return build_bracketing_solution(prob, alg, left, fl, left, right, ReturnCode.FloatingPointLimit)
        end

        mid = (fr * left - fl * right) / (fr - fl)
        for _ in 1:10
            mid = Impl.max_tdir(left, Impl.prevfloat_tdir(mid, l, r), l, r)
        end

        (mid == left || mid == right) && break

        fm = f(mid)
        if iszero(fm)
            return build_exact_solution(prob, alg, mid, fm, ReturnCode.Success)
        end

        if abs((right - left) / 2) < abstol
            return build_bracketing_solution(prob, alg, mid, fm, left, right, ReturnCode.Success)
        end

        if abs(fm) < abstol
            right = mid
            break
        end

        if sign(fl) == sign(fm)
            fl, left = fm, mid
        else
            fr, right = fm, mid
        end

        i += 1
    end

    # Fallback to bisection solver
    return internal_bisection(f, left, right, fl, fr, abstol, maxiters - i, prob, alg)
end
