I might as well elaborate on my comment. Here is a modification of Stan Wagon's FindAllCrossings[]
function (from his book Mathematica in Action, second edition) that uses Plot[]
to generate the initial approximations to be subsequently polished by FindRoot[]
:
Options[FindAllCrossings] =
Sort[Join[Options[FindRoot], {MaxRecursion -> Automatic,
PerformanceGoal :> $PerformanceGoal, PlotPoints -> Automatic}]];
FindAllCrossings[f_, {t_, a_, b_}, opts___] := Module[{r, s, s1, ya},
{r, ya} = Transpose[First[Cases[Normal[
Plot[f, {t, a, b}, Method -> Automatic,
Evaluate[Sequence @@
FilterRules[Join[{opts}, Options[FindAllCrossings]],
Options[Plot]]]]], Line[l_] :> l, Infinity]]];
s1 = Sign[ya]; If[ ! MemberQ[Abs[s1], 1], Return[{}]];
s = Times @@@ Partition[s1, 2, 1];
If[MemberQ[s, -1] || MemberQ[Take[s, {2, -2}], 0],
Union[Join[Pick[r, s1, 0],
Select[t /. Map[FindRoot[f, {t, r[[#]], r[[# + 1]]},
Evaluate[Sequence @@
FilterRules[Join[{opts}, Options[FindAllCrossings]],
Options[FindRoot]]]] &,
Flatten[Position[s, -1]]], a <= # <= b &]]], {}]]
Try it out:
FindAllCrossings[BesselJ[1, x]^2 + BesselK[1, x]^2 - Sin[Sin[x]], {x, 0, 100},
WorkingPrecision -> 20]
{0.88660463531346207679, 3.0329660890136683539,
6.3239665137114782212, 9.3911434075850854017, 12.589067252797192964,
15.687789316501627036, 18.865248000326751595, 21.976728589463954937,
25.144727536576135544, 28.263111694495812775, 31.425621611972587076,
34.548333253230934213, 37.707250582575859710, 40.832929091244028281,
43.989309899299199529, 47.117149292753968158, 50.271642808648651326,
53.401126310508732375, 56.554160423425108364, 59.684936863656120488,
62.836808589969946989, 65.968628466404205710, 69.119552435670107405,
72.252232119042699356, 75.402368490602128759, 78.535768909563822046,
81.685240379776511855, 84.819253682565487033, 87.968156330842562535,
91.102697190752433240, 94.251107663305908556, 97.386107414041584404}
A different implementation involves the use of the MeshFunctions
option of Plot[]
to generate the seeds. Here's how it looks:
FindAllCrossings[f_, {t_, a_, b_}, opts : OptionsPattern[]] := Module[{r},
r = Cases[Normal[Plot[f, {t, a, b}, MeshFunctions -> (#2 &), Mesh -> {{0}},
Method -> Automatic, Evaluate[Sequence @@
FilterRules[Join[{opts}, Options[FindAllCrossings]],
Options[Plot]]]]],
Point[p_] :> SetPrecision[p[[1]], OptionValue[WorkingPrecision]],
Infinity];
If[r =!= {},
Union[Select[t /. Map[FindRoot[f, {t, #}, Evaluate[Sequence @@
FilterRules[Join[{opts},
Options[FindAllCrossings]],
Options[FindRoot]]]] &, r],
a <= # <= b &]], {}]]
This version might be a bit faster in some cases, but it no longer has the safety feature of root bracketing in the previous version.
Plot[]
to find initial approximations forFindRoot[]
. If you're interested in that approach, I can write up an answer. $\endgroup$Reduce[]
-based methods: all of these hinge on the fact thatReduce[]
apparently knows quite a fair bit about the transcendental functions built within Mathematica. If, however, you are dealing with a black-box function that can only evaluate at numerical values (you can simulate this behavior with something likef[x_?NumericQ] := Haversine[Pi x]
), thenReduce[]
won't be able to do much. $\endgroup$