I would like to argue that this is a bug.
The roots are roughly located and polished with FindRoot
at a WorkingPrecision
of 10
plus the WorkingPrecision
of NSolve
. In this case that is ten more than machine precision, or MachinePrecision + 10
, which is about 26.95
digits.
We can see that all 32 roots are found.
fn = BesselJ[0, #] &; (* for convenience *)
rts0 = Trace[
NSolve[{BesselJ[0, x], 0 < x < 100}, x, Reals],
HoldPattern[f : FindRoot[_, {v_, _}, ___]] :> (v /. f),
TraceInternal -> True] // Flatten // ReleaseHold // Sort;
Plot[fn[x], {x, 0, 100},
PlotLabel -> Row[{Length@rts, "roots"}, " "],
Epilog -> {Red, Point@Thread[{rts0, 0}]}]
NSolve
then set the roots to the arbitrary-precision equivalent of the working precision, which in this case is $MachinePrecision
and deletes the value of x
for which fn[x]
is nonzero:
rts = SetPrecision[rts0, $MachinePrecision];
ListPlot[
fn[rts] /. r_ /; r == 0 :> 0 // RealExponent,
GridLines -> {Flatten@Position[fn[rts], r_ /; r != 0], None},
PlotLabel ->
"Indices of final roots, rejected with nonzero residual"
]
Trace[
NSolve[{BesselJ[0, x], 0 < x < 100}, x, Reals],
HoldPattern[Select[_, Function[_Equal]]],
TraceInternal -> True] // Flatten
The real problem is that at an arbitrary-precision of $MachinePrecision
there is no number near each discarded root that can make the Bessel function evaluate to an arbitrary-precision zero. (It's the nature of a finite machine that not every real number can be represented.) Usually what happens at the closest arbitrary-precision number to a root is that the round-off error bound calculated by the arbitrary-precision code is greater than the computed value of fn[x]
at a zero x
, and an arbitrary-precision zero is returned. I suspect the assumption was that this always happens, but apparently it does not.
NSolve[{BesselJ[0, x], 0 < x < 100 }, x, Reals]
$\endgroup$