By playing with the tolerance, you can find all roots with the following code (using @Tamas_Papp’s definition of f). I would say that interval methods are not overkill – which other method would be able to find all of these roots, and guarantee that they are indeed all of the roots in that box?
julia> rts = roots(f, IntervalBox(-100..100, 2), 1e-14)
114-element Array{IntervalRootFinding.Root{IntervalArithmetic.IntervalBox{2,Float64}},1}:
Root([0.0404036, 0.0404037] × [98.879, 98.8791], :unique)
Root([0.03142, 0.0314201] × [97.4523, 97.4524], :unique)
Root([0.0208864, 0.0208865] × [95.7767, 95.7768], :unique)
Root([0.0311381, 0.0311382] × [94.3102, 94.3103], :unique)
Root([0.0431404, 0.0431405] × [92.5903, 92.5904], :unique)
Root([0.033631, 0.0336311] × [91.1736, 91.1737], :unique)
Root([0.0223543, 0.0223544] × [89.4906, 89.4907], :unique)
Root([0.0333079, 0.033308] × [88.0313, 88.0314], :unique)
Root([0.0462746, 0.0462747] × [86.3007, 86.3008], :unique)
Root([0.0361763, 0.0361764] × [84.8955, 84.8956], :unique)
⋮
Root([-0.0345102, -0.0345101] × [-84.8923, -84.8922], :unique)
Root([-0.0231685, -0.0231684] × [-86.3475, -86.3474], :unique)
Root([-0.0348574, -0.0348573] × [-88.0346, -88.0345], :unique)
Root([-0.0446527, -0.0446526] × [-89.4457, -89.4456], :unique)
Root([-0.0321866, -0.0321865] × [-91.1708, -91.1707], :unique)
Root([-0.0215955, -0.0215954] × [-92.6338, -92.6337], :unique)
Root([-0.0324881, -0.032488] × [-94.313, -94.3129], :unique)
Root([-0.0417273, -0.0417272] × [-95.7348, -95.7347], :unique)
Root([-0.0301559, -0.0301558] × [-97.4499, -97.4498], :unique)
Root([-0.0202226, -0.0202225] × [-98.9197, -98.9196], :unique)
julia> all([rt.status for rt in rts] .== :unique)
true
By the way, for simpler functions you can even guarantee that you have found all (real) roots.
Using the master branch of IntervalRootFinding.jl, we have the following using an infinite initial box in 2D.
This is certainly impossible with any method that is not set-based.
julia> f(x, y) = SVector(x^2 + y^2 - 1, y - x)
f (generic function with 1 method)
julia> f(X) = f(X...)
f (generic function with 2 methods)
julia> rts = roots(f, IntervalBox(-∞..∞, 2))
2-element Array{IntervalRootFinding.Root{IntervalArithmetic.IntervalBox{2,Float64}},1}:
Root([0.707106, 0.707107] × [0.707106, 0.707107], :unique)
Root([-0.707107, -0.707106] × [-0.707107, -0.707106], :unique)