Primes Race (Mathematica Efficiency)
The solution is fairly simple,
Prime[Sign@Accumulate[Mod[Prime@Range@PrimePi[1*^6],4]-2]~Position~-1]
where
Prime@Range@PrimePi[1*^6]
gives the list of all primes up to1*^6
;Mod[...,4]-2
automatically threads over the list above, giving1
or-1
for two teams respectively. Note thatMod[2,4]-2
equals to0
.Sign@Accumulate[...]
gives a list of results about which team is leading so far.Prime[...~Position~-1]
gives all primes team 2 is leading when up to which.
It takes 0.056s on my laptop to get the final result,
{{26861},{616841},{616849},...,{633653},{633667},{633797}}
Other techniques
Here are some techniques to improve performance, but be less elegant.
Mod[#,4]& --> BitAnd[#,3]&
Position[#,-1]& --> Pick[Range@Length@#,#,-1]
; they are expressing the same idea in this case.
Improved Solution
The challenge posed in the question is determine for any x
up to M = 1000000
whether list1
or list2
has more elements less than x
. The question suggests that M
primes are needed to make that determination. In fact, only the substantially smaller (by a factor of about 0.08
) set of primes less than or equal to M
is needed. It is computed by
M = 1000000;
listPrimes = Table[Prime[i], {i, 1, PrimePi[M]}];
list1 = Select[listPrimes, Mod[#1, 4] == 3 &];
list2 = Select[listPrimes, Mod[#1, 4] == 1 &];
Next, we count the number of primes less than any integer from 1
to M
.
listm = Append[Prepend[list1, 1], M + 1];
count1 = Flatten@Table[ConstantArray[i - 1, listm[[i + 1]] - listm[[i]]],
{i, Length[listm] - 1}];
listm = Append[Prepend[list2, 1], M + 1];
count2 = Flatten@Table[ConstantArray[i - 1, listm[[i + 1]] - listm[[i]]],
{i, Length[listm] - 1}];
and Tally
the number of instances that one or the other list is ahead.
Tally@MapThread[Sign[#1 - #2] &, {count1, count2}]
(* {{0, 1352}, {1, 995242}, {-1, 3406}} *)
list1
is ahead for 995242
values of integer x
between 1
and M
, list2
ahead for 3406
values of x
, and the lists are tied for 1352
values of x
. The first ten x
, for instance, at which list2
is ahead is given by
Flatten@Position[MapThread[Sign[#1 - #2] &, {count1, count2}], -1][[1 ;; 10]]
(* {26861, 26862, 616841, 616842, 616849, 616850, 616851, 616852, 616853, 616854} *)
The AbsoluteTiming
for this entire calculation is about 1.9 sec on my PC.
Solution for M = 100000000
My 8 GB PC can just barely handle M = 100000000
, requiring about 200 sec and over 8.2 GB (some on disk). Thus, run time varies linearly with M
, as expected. (Larger M
could be handled by breaking the calculation into parts to reduce memory usage.) The Tally
results are
(* {{0, 3866}, {1, 99965510}, {-1, 30624}} *)
The list2
"wins" are clustered into three groups, much as shown in the earlier plot below.
Earlier Solution
This earlier solution was derived for 1000000
primes. It compares the magnitude of the nth prime of list1
with that of list2
. Whichever list has the smaller prime is ahead at that point. In effect, it involves sampling but nonetheless gives a good qualitative picture of the behavior of the race.
Count[MapThread[#1 < #2 &, {list1[[1 ;; Length[list2]]], list2}], False]
(* 1034 *)
Thus, there are 1034 instances among the first million primes in which a list1
element is larger than the corresponding list2
element. The first one is readily found with
Position[MapThread[#1 < #2 &, {list1[[1 ;; Length[list2]]], list2}][[1 ;; 10000]], False]
(* {{1473}} *)
{list1[[%[[1, 1]]]], list2[[%[[1, 1]]]]}
(* {26863, 26861} *)
The distribution of rare cases can be plotted as follows.
ListPlot[{#, list1[[#]]} & /@ Flatten@Position[
MapThread[#1 < #2 &, {list1[[1 ;; Length[list2]]], list2}], False],
PlotRange -> {{1, Length[list2]}, {1, list2[[-1]]}}]
So, the rare cases where a list1
element is larger than the corresponding list2
element are clustered into just three groups, the first barely visible near the origin. Closer examination reveals that there is 1 case in the first cluster, about 150 cases in the second, and about 1330 in the third.