3
$\begingroup$

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.

$\endgroup$

2 Answers 2

4
$\begingroup$

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

version

list = RandomReal[10, 10^5];

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

pic1

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

pic2

$\endgroup$
2
  • 1
    $\begingroup$ Brilliant explanation, thanks bmf! $\endgroup$
    – Chris
    Commented Feb 18, 2023 at 13:35
  • $\begingroup$ @Chris glad I was able to help :) $\endgroup$
    – bmf
    Commented Feb 18, 2023 at 13:37
6
$\begingroup$

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}}


$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.