# Position command runs much slower for range containing numerically evaluated Bessel function

I have a long list (about 10000) of positive numbers (here simply denoted list), for which I want to find the positions of elements lying between 0.5 and the first zero of the Bessel function of the first kind of order 1, as shown below:

Flatten[Position[
list, _?(0.5 <= # <= 3.83171 &)], 1];
Flatten[Position[
list, _?(0.5 <= # <= N[BesselJZero[1, 1]] &)],
1];


The first code runs in a fraction of a second whereas the second takes about a minute and I can't figure out why. Please can someone advise what's going wrong? I really want to use the second line of code because I'm extending it to many ranges involving zeros of Bessel functions, but currently it's taking far too long. Thanks in advance for any help.

I hope that this is sufficient for your needs. Essentially, you were using the numerical value of the BesselZero with MachinePrecision. You can opt to use the second argument of N to obtain the n‐digit precision of the BesselZero.

\$Version


list = RandomReal[10, 10^5];

Flatten[Position[list, _?(0.5 <= # <= 3.83171 &)],
1] // AbsoluteTiming


Flatten[Position[list, _?(0.5 <= # <= N[BesselJZero[1, 1], 6] &)],
1] // AbsoluteTiming


• Brilliant explanation, thanks bmf! Commented Feb 18, 2023 at 13:35
• @Chris glad I was able to help :)
– bmf
Commented Feb 18, 2023 at 13:37

Speed will suffer if the condition is evaluated inside Positionon every pass.

OP - preevaluated condition

list = RandomReal[{0, 5}, 10000];
Flatten[Position[list, _?(0.5 <= # <= 3.83171 &)], 1] //
AbsoluteTiming // Short


{0.0248739,{1,<<6662>>,10000}}

OP Slower case

If you evaluate (0.5 <= # <= N[BesselJZero[1, 1]] &) separately, the result is:

0.5 <= #1 <= N[BesselJZero[1, 1]] &

Thus Position is presented with an unevaluated condition on every pass, thereby incurring a time penalty.

Workaround

Evaluate the upper limit once inside With:

With [{a = N[BesselJZero[1, 1]]},
Flatten[Position[list, _?(0.5 <= # <= a &)], 1]
] // AbsoluteTiming // Short


{0.0178069,{1,<<6662>>,10000}}

Or if you prefer, define and evaluate the upper limit inside the cond first:

cond = (0.5 <= #1 <= N@BesselJZero[1, 1] // Evaluate) &
Flatten[Position[list, _?cond], 1] // AbsoluteTiming // Short
`

{0.0169222,{1,<<6662>>,10000}}