Addendum
If you just want the greatest 10 primes less than M, you can start from Prime[PrimePi[M]-9]
. By doing so, you gain a speed increase of 2 orders of magnitude when M = 100000
.
M = 100000;
m = PrimePi[M]
AbsoluteTiming[Table[Prime[k], {k, m - 9, m}]]
9592
{0.000171, {99877, 99881, 99901, 99907, 99923, 99929, 99961, 99971, 99989, 99991}}
Now backwards (after closing and re-opening Mathematica and defining M
and m
.).
This is 10 x slower than the above, but still faster than starting from Prime[1]
.
AbsoluteTiming[Table[Prime[k], {k, m, m - 9, -1}]]
{0.001467, {99991, 99989, 99971, 99961, 99929, 99923, 99907, 99901, 99881, 99877}}
One might expect that NextPrime
would provide an advantage. We restart Mathematica and find out that it is only marginally better than our last attempt.
AbsoluteTiming[NestList[NextPrime, Prime[m - 9], 9]]
{0.001193, {99877, 99881, 99901, 99907, 99923, 99929, 99961, 99971, 99989, 99991}}
My Earlier answers about the order of the iterator.
I conducted the following tests starting at Prime[1]
. Even though this is a very inefficient approach, the results will be easier to compare to those of the OP.
We want to rule out Range
so we take it out of the timing. Likewise, we set M
and m
first, before conducting the timing.
M = 100000;
m = PrimePi[M];
r1 = Range[1, m];
r2 = Range[m, 1, -1];
Backwards request of primes much slower than forwards request (the original observation)
r1 == Reverse[r2]
AbsoluteTiming[prms = Prime[#] & /@ r1;]
AbsoluteTiming[prms = Prime[#] & /@ r2;]
True
{0.009920, Null}
{0.354147, Null}
Puzzling. Yet absolutely consistent with what you observed.
It appears that r1
may be stored in a form that can be processed more quickly than r2
.
Half backwards, Half forwards: Only half as bad as all backwards.
Let's look a little deeper.
r3
is the sub-list of odd numbers, followed by the even numbers.
r5
is like r3
but the odd numbers were reversed.
r3 = Transpose[Partition[r1, 2]] // Flatten;
r4 = Transpose[Partition[r1, 2]];
r5 = Join[Reverse[r4[[1]]], r4[[2]]];
Let's time the processing of r3 and r5:
AbsoluteTiming[prms = Prime[#] & /@ r3;]
AbsoluteTiming[prms = Prime[#] & /@ r5;]
{0.012765, Null}
{0.205590, Null}
Half the numbers in r5 were ordered from larger to smaller.
The delay was about 1/2 the delay we saw when all numbers were ordered from larger to smaller.
Provisional conclusion: Mathematica "counts" primes forwards faster than backwards(?)
Random Ordering
r6 = RandomSample[r1, 9592];
AbsoluteTiming[prms = Prime[#] & /@ r6;]
{0.190770, Null}
The (pseudo)random ordering of numbers runs as fast as the backwards-forwards list!
Lingering Question: Why should a random ordering of numbers be faster to process than a "backwards request" for primes? I would have guessed that the random case would be at least as slow, or slower than the backward case.
P.S. @Szabolcs Please look at the results above and see whether they are consistent with your hunch. (I'm uncertain whether they are.) Perhaps Mathematica only stores the results of the final outcome. In this case the backwards request would receive no benefits.
Szabolcs' suggestion
Here are some orderings recommended by Szabolcs. Notice how the orderings increasingly move toward canonical ordering from least to greatest.
Table[{k, First@Timing[
Prime /@ Flatten@Reverse@Partition[Range[1, 20], k]]}, {k, 1, 10}];
Table[{k, Prime /@ Flatten@Reverse@Partition[Range[1, 20], k]}, {k, 1,10}]
And their respective timings:
Table[{k, First@Timing[Prime /@ Flatten@Reverse@Partition[Range[1, 20000], k];]}, {k, 1,10}]
{{1, 2.540567}, {2, 1.275608}, {3, 0.858899}, {4, 0.647391}, {5,
0.517372}, {6, 0.431639},
{7, 0.370851}, {8, 0.325734}, {9, 0.291674}, {10, 0.262256}}
Here's the canonical ordering:
First@Timing[Prime /@ Flatten@Partition[Range[1, 20000], 1];]
0.011894
Prime[n]
makes use of results forPrime[m], m < n
, but it caches only a limited number of results. But this is just a guess and you have surely though of it already. $\endgroup$Prime
andPrimePi
areListable
, they are automatically mapped over a list, thus you can simply write e.g.Prime @ Range @ m
instead ofPrime[#] & /@ Range[1, m]
. $\endgroup$