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$ Commented Feb 18, 2023 at 13:35
  • $\begingroup$ @Chris glad I was able to help :) $\endgroup$ 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$

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.